4

カスタム動作を追加するために辞書から継承するクラスがあります。この場合、検証のために各キーと値を関数に渡します。以下の例では、「検証」は単純にメッセージを出力します。

ディクショナリへの割り当ては期待どおりに機能し、アイテムがディクショナリに追加されるたびにメッセージが出力されます。しかし、カスタム辞書タイプを__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}

誰かが私が期待したように動作しない理由を説明できますか? それは私が試みているように機能しますか、それとも機能しませんか?

4

1 に答える 1

5

これは最適化です。でメタメソッドをサポートするには__dict__、インスタンスの割り当てごとにメタメソッドの存在を確認する必要があります。これは基本的な操作であり、すべての属性のルックアップと代入です。そのため、これをチェックするために必要な余分ないくつかの分岐は、多かれ少なかれ and と冗長な何かのために、言語全体のオーバーヘッドになりobj.__getattr__ますobj.__setattr__

于 2011-03-03T17:33:31.407 に答える