Odd behavior using custom dict class as attribute of __dict__ of Python classes

I have a class that inherits from a dictionary to add some kind of custom behavior - in this case it passes each key and the value of the function to be checked. In the example below, a "check" simply prints a message.

Dictionary assignment works as expected, printing messages whenever elements are added to the dict. But when I try to use a custom word type as an __dict__ attribute for a class, assigning attributes that in turn put keys / values ​​into my custom dictionary class, somehow I manage to insert values ​​into the dictionary, completely bypassing __setitem__ (and other methods that I determined which keys can add).

User Dictionary:

 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 

Using it as an attribute of the __dict__ class gives behavior that I don't understand.

 >>> 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} 

Can someone explain why it is not behaving as I expect? Maybe he or he can't work the way I'm trying?

+4
source share
1 answer

This is an optimization. To support metamethods on __dict__ , each instance assignment would have to verify the existence of the metamethod. This is a fundamental operation β€” each attribute search and assignment β€” therefore, the additional branches of the pair needed to verify this will become overhead for the whole language, for something more or less redundant with obj.__getattr__ and obj.__setattr__ .

+5
source

Source: https://habr.com/ru/post/1342149/


All Articles