“dict”何时重新初始化?

2024-09-30 04:35:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我将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

谢谢你的解释


Tags: keyselfidreturn属性initvaluedef
2条回答

要实现您想要的,您应该覆盖__getattr____setattr____delattr__

class DictWithAttr(dict):

    def __getattr__(self, name):
        return self[name]

    __setattr__ = dict.__setitem__

    def __delattr__(self, name):
        del self[name]

    def __dir__(self):
        return dir({}) + list(self.keys())

用户2357112已经指出了问题的原因

没有重新初始化。你的问题是self.__dict__ = self击中了你的__setattr__覆盖。它实际上并没有改变用于属性查找的dict。它为self上的'__dict__'键设置一个条目,并保持dict属性不变

如果您想保留(无意义的)__setattr__重写,可以在__init__中绕过它:

object.__setattr__(self, '__dict__', self)

但是去掉__setattr__覆盖会更容易。当你在做的时候,把__repr__也去掉——一旦你修复了你的代码,出现'__dict__'键的唯一原因就是如果用户自己设置了它,如果他们这样做了,你应该显示它

相关问题 更多 >

    热门问题