回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>我将<code>dict</code>子类化,以便属性与键相同:</p>
<pre><code>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__'})
</code></pre>
<p>它的工作原理与预期一致:</p>
<pre><code>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
</code></pre>
<p>但是如果我把<code>__setattr__</code>重写为</p>
<pre><code> ...
def __setattr__(self, key, value):
self[key] = value
...
</code></pre>
<p>然后<code>__dict__</code>将在初始化中重新创建,属性将变为不可访问:</p>
<pre><code>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'
</code></pre>
<p>如下所示添加成对的<code>__getattr__</code>将绕过<code>AttributeError</code></p>
<pre><code> ...
def __getattr__(self, key):
return self[key]
...
</code></pre>
<p>但仍然<code>__dict__</code>被清除:</p>
<pre><code>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
</code></pre>
<p>谢谢你的解释</p>