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

Odd behaviour using a custom dict class as the __dict__ attribute of Python classes

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

对字典的赋值按预期工作,在向字典中添加项时打印消息。但当我尝试使用自定义字典类型作为类的__dict__属性时,属性赋值(反过来又将键/值放入自定义字典类)会设法在完成时将值插入字典。ely绕过__setitem__(以及我定义的其他可能添加键的方法)。

自定义词典:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> 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}

有人能解释一下为什么它不像我期望的那样表现吗?它能不能像我想的那样工作?


这是一个优化。为了支持__dict__上的元方法,每个实例分配都需要检查元方法的存在性。这是一个基本的操作——每个属性的查找和分配——因此检查这一点所需的额外的耦合分支将成为整个语言的开销,因为这些分支或多或少与obj.__getattr__obj.__setattr__冗余。