Reputation: 2025
I try to understand subclassing of collections.abc.MutableMapping
. I've created my own version of dict
that prints some info:
from collections.abc import MutableMapping
class MutableMappingTest(MutableMapping):
def __init__(self, *args, **kwargs):
print('__init__', args, kwargs)
self.my_store = dict()
self.update(dict(*args, **kwargs))
def __getitem__(self, key):
print('__getitem__:', key)
return self.my_store[key]
def __setitem__(self, key, value):
print('__setitem__:', key, value)
self.my_store[key] = value
def __delitem__(self, key):
print('__delitem__:', key)
del self.my_store[key]
def __iter__(self):
print('__iter__')
return iter(self.my_store)
def __len__(self):
print('__len__')
return len(self.my_store)
What I do not understand: When I update by assigning to a nested attribute, __setitem__
is not called, just __getitem__
:
>>> t = MutableMappingTest(test={"deep": "foo"})
__init__ () {'test': {'deep': 'foo'}}
__setitem__: test {'deep': 'foo'}
>>> t['test']['deep'] = 'bar'
__getitem__: test
How can I also hook into updating nested attributes. Do I have to override update()? How is that done?
Upvotes: 0
Views: 1161
Reputation: 60974
Because you're not setting an item in t
. Instead, you're getting a regular dictionary from t
, and then setting an item in that dictionary.
If you want the sub dictionaries to behave like MutableMappingTest
objects, you have to make them MutableMappingTest
objects.
>>> t = MutableMappingTest(test=MutableMappingTest(deep="foo"))
__init__ () {'deep': 'foo'}
__setitem__: deep foo
__init__ () {'test': <__main__.MutableMappingTest object at 0x000001EA3C1DDB00>}
__setitem__: test <__main__.MutableMappingTest object at 0x000001EA3C1DDB00>
>>> t['test']['deep'] = 'bar'
__getitem__: test
__setitem__: deep bar
Upvotes: 1