我将dict
子类化,以便属性与键相同:
class DictWithAttr(dict):
def __init__(self, *args, **kwargs):
self.__dict__ = self
super(DictWithAttr, self).__init__(*args, **kwargs)
print(id(self), id(self.__dict__))
def copy(self):
return DictWithAttr(self.__dict__)
def __repr__(self):
return repr({k:v for k, v in self.items() if k != '__dict__'})
它的工作原理与预期一致:
d = DictWithAttr(x=1, y=2) # 139917201238328 139917201238328
d.y = 3
d.z = 4
d['w'] = 5
print(d) # {'x': 1, 'y': 3, 'z': 4, 'w': 5}
print(d.__dict__) # {'x': 1, 'y': 3, 'z': 4, 'w': 5}
print(d.z, d.w) # 4 5
但是如果我把__setattr__
重写为
...
def __setattr__(self, key, value):
self[key] = value
...
然后__dict__
将在初始化中重新创建,属性将变为不可访问:
d = DictWithAttr(x=1, y=2) # 140107290540344 140107290536264
d.y = 3
d.z = 4
d['w'] = 5
print(d) # {'x': 1, 'y': 3, 'z': 4, 'w': 5}
print(d.__dict__) # {}
print(d.z, d.w) # AttributeError: 'DictWithAttr' object has no attribute 'z'
如下所示添加成对的__getattr__
将绕过AttributeError
...
def __getattr__(self, key):
return self[key]
...
但仍然__dict__
被清除:
d = DictWithAttr(x=1, y=2) # 139776897374520 139776897370944
d.y = 3
d.z = 4
d['w'] = 5
print(d) # {'x': 1, 'y': 3, 'z': 4, 'w': 5}
print(d.__dict__) # {}
print(d.z, d.w) # 4 5
谢谢你的解释
要实现您想要的,您应该覆盖
__getattr__
、__setattr__
和__delattr__
用户2357112已经指出了问题的原因
没有重新初始化。你的问题是
self.__dict__ = self
击中了你的__setattr__
覆盖。它实际上并没有改变用于属性查找的dict。它为self
上的'__dict__'
键设置一个条目,并保持dict属性不变如果您想保留(无意义的)
__setattr__
重写,可以在__init__
中绕过它:但是去掉
__setattr__
覆盖会更容易。当你在做的时候,把__repr__
也去掉——一旦你修复了你的代码,出现'__dict__'
键的唯一原因就是如果用户自己设置了它,如果他们这样做了,你应该显示它相关问题 更多 >
编程相关推荐