Странное поведение при использовании пользовательского класса dict в качестве атрибута __dict__ классов Python - PullRequest
4 голосов
/ 03 марта 2011

У меня есть класс, который наследует от словаря для добавления некоторого пользовательского поведения - в этом случае он передает каждый ключ и значение в функцию для проверки. В приведенном ниже примере «проверка» просто печатает сообщение.

Присвоение словарю работает должным образом, печатая сообщения всякий раз, когда элементы добавляются в 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 голосов
/ 03 марта 2011

Это оптимизация. Для поддержки метаметодов на __dict__ каждое назначение экземпляра должно проверять наличие метаметода. Это фундаментальная операция - поиск и присваивание каждого атрибута - так что дополнительные ветви пары, необходимые для проверки этого, станут непроизводительными для всего языка, для чего-то, что более или менее избыточно с obj.__getattr__ и obj.__setattr__.

...