使用自定义dict类作为Python类的__dict__属性的奇怪行为

por*_*uod 4 python attributes metaprogramming magic-methods

我有一个继承自字典的类,以便添加一些自定义行为 - 在这种情况下,它将每个键和值传递给一个函数进行验证.在下面的示例中,"验证"只是打印一条消息.

字典的分配按预期工作,每当项目添加到字典时打印消息.但是当我尝试使用自定义字典类型作为__dict__类的属性时,属性赋值又将键/值放入我的自定义字典类中,以某种方式设法在完全绕过时将值插入字典中__setitem__(以及其他方法我已定义可能添加密钥).

自定义词典:

from collections import MutableMapping
class ValidatedDict(dict):
    """A dictionary that passes each value it ends up storing through
    a given validator function.
    """
    def __init__(self, validator, *args, **kwargs):
        self.__validator = validator
        self.update(*args, **kwargs)
    def __setitem__(self, key, value):
        self.__validator(value)
        self.__validator(key)
        dict.__setitem__(self, key, value)
    def copy(self): pass # snipped
    def fromkeys(validator, seq, v = None): pass # snipped
    setdefault = MutableMapping.setdefault
    update = MutableMapping.update

def Validator(i): print "Validating:", i
Run Code Online (Sandbox Code Playgroud)

使用它作为__dict__类的属性产生我不理解的行为.

>>> d = ValidatedDict(Validator)
>>> d["key"] = "value"
Validating: value
Validating: key
>>> class Foo(object): pass
... 
>>> foo = Foo()
>>> foo.__dict__ = ValidatedDict(Validator)
>>> type(foo.__dict__)
<class '__main__.ValidatedDict'>
>>> foo.bar = 100 # Yields no message!
>>> foo.__dict__['odd'] = 99
Validating: 99
Validating: odd
>>> foo.__dict__
{'odd': 99, 'bar': 100}
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么它的行为不符合我的预期吗?它可以或不能以我正在尝试的方式工作吗?

Gle*_*ard 5

这是一个优化.为了支持元方法__dict__,每个实例分配都需要检查元方法的存在.这是一个基本的操作 - 每个属性查找和赋值 - 所以检查这个的额外的几个分支将成为整个语言的开销,对于或多或少冗余的obj.__getattr__obj.__setattr__.

  • 我称之为Python文档没有明确提及的错误.*class*docs(不是*类实例*)特别说`Cx被翻译为C .__ dict __ ["x"]`,人们很容易看到它并假设类实例也是如此,所以这个可以更清楚.http://docs.python.org/reference/datamodel.html (3认同)