由题
不多说直接上代码
分析见下
class dot:
def __init__(self, d=None):
if d is not None:
for k,v in d.items():
if isinstance(v, dict):
self[k] = dy(v)
else:
self[k] = v
#可选的函数定义
def __str__(self):
return __import__("json").dumps(self.__dict__)
#必须的函数定义
def __setattr__(self, key, value):
self.__dict__[key] = value
def __getattr__(self, key):
return self.__dict__[key]
def __getitem__(self, key):
return self.__dict__.__getitem__(key)
def __setitem__(self, key, value):
return self.__dict__.__setitem__(key, value)
#可选的函数定义
def keys(self):
return self.__dict__.keys()
def copy(self):
return self.__dict__.copy()
def pop(self, keys):
return self.__dict__.pop(keys)
def items(self):
return self.__dict__.items()
def values(self):
return self.__dict__.values()
#...
所有的attr与item都被保存到了dict下
即分别重定义了__getattr__, __setattr__, __getitem__, __setitem__
四个函数
甚至不需要继承dict类(欢喜
另外单独定义了values, items等等的dict类原生函数而不是使用类似values = __dict__.values
这样的写法, 这样不仅能正常调用而且返回中也不会包括这些函数名
要点在于重定义了__getattr__
而不是__getattribute__
在调用这些函数时会首先调用正常的__getattribute__
, 正常地找到这些函数并正常地调用, 而当调用后来赋值的attr或item则__getattribute__
找不到对应的值便调用__getattr__
在__dict__
里找, 万事大吉
需要注意的是这些原生函数只能通过点语法调用(废话), 也能作为字段名重新赋值(还是废话)
一个点字典可以实现以下操作
- 转化原生字典
a = dot({"x":1, "y":2})
- 调用dict原生函数(需要单独定义)
a.values()
- 同时使用点语法与字段名取赋值
a.t = 5
ora["t"] = 5
另外需要注意当进行了如a[1] = ...
这种给数字索引的赋值的操作后dir(a)
会报错, 具体原因未知
不过即使如此取值也是没问题的
empty