使用自定义字典类作为Python类的__dict__属性时的异常行为
我有一个类,它是从字典继承来的,目的是为了添加一些自定义的功能。在这个例子中,它会把每一个键和值传递给一个函数进行验证。在下面的例子中,这个“验证”只是简单地打印一条消息。
把东西放进这个字典时,一切都按预期工作,每当往字典里添加项目时,都会打印消息。但是,当我试图把这个自定义字典类型用作一个类的 __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
把它用作类的 __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}
有人能解释一下为什么它没有按我预期的方式工作吗?这样做到底能不能实现?
1 个回答
5
这是一个优化的过程。为了在 __dict__
上支持元方法,每次给实例赋值的时候都需要检查一下这个元方法是否存在。这是一个非常基础的操作——每次查找和赋值属性的时候都要做这个检查。所以,如果每次都多出几步来检查,就会给整个语言带来额外的负担,而这些检查其实和 obj.__getattr__
和 obj.__setattr__
的功能差不多,算是多余的。