使用自定义字典类作为Python类的__dict__属性时的异常行为

4 投票
1 回答
953 浏览
提问于 2025-04-16 12:56

我有一个类,它是从字典继承来的,目的是为了添加一些自定义的功能。在这个例子中,它会把每一个键和值传递给一个函数进行验证。在下面的例子中,这个“验证”只是简单地打印一条消息。

把东西放进这个字典时,一切都按预期工作,每当往字典里添加项目时,都会打印消息。但是,当我试图把这个自定义字典类型用作一个类的 __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__ 的功能差不多,算是多余的。

撰写回答