This question has been partially answered in this thread : How to correctly implement the mapping protocol in Python? But I encounter a problem that makes me think that this answer is not enough.
The python documentation (https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes) states that the Mapping abstract base class has 3 abstract methods (__getitem__
, __iter__
and __len__
) that must be implemented by any concrete subclass.
The others methods are mixin methods, and they should not need to be re-implemented.
But if I define a class like this one :
class MappingView(Mapping):
def __init__(self, impl=None):
if None is impl:
impl = dict()
self._impl = impl
def __getitem__(self, key):
return self._impl[key]
def __len__(self):
return len(self._impl)
def __iter__(self):
return iter(self._impl)
1/ Implemented abstract methods work fine :
dv = MappingView({'key1': 'val1', 'key2': 'val2'})
print(dv['key2']) # val2
print(len(dv)) # 2
for key in dv:
print(key) # key1, key2
2/ Some mixin methods work fine too :
dv = MappingView({'key1': 'val1', 'key2': 'val2'})
print('key1' in dv) # True
print('key3' in dv) # False
3/ But some others don't work :
dv = MappingView({'key1': 'val1', 'key2': 'val2'})
print(dv.keys()) # KeysView(<utils.MappingView object at 0x7fd1aa349ac0>) instead of dict_keys(['key1', 'key2'])
print(dv.values()) # ValuesView(<utils.MappingView object at 0x7fd1aa349ac0>) instead of dict_values(['val1', 'val2'])
print(dv.items()) # ItemsView(<utils.MappingView object at 0x7fd1aa349ac0>) instead of dict_items([('key1', 'val1'), ('key2', 'val2')])
This is because the current implementation of these methods is : (https://github.com/python/cpython/blob/3.11/Lib/_collections_abc.py#L786)
def keys(self):
"D.keys() -> a set-like object providing a view on D's keys"
return KeysView(self)
def items(self):
"D.items() -> a set-like object providing a view on D's items"
return ItemsView(self)
def values(self):
"D.values() -> an object providing a view on D's values"
return ValuesView(self)
How to subclass Mapping abstract base class without having to re-implements mixin methods ?