I am trying to subclass a python dictionary __getitem__
method while maintaining the original class type when accessing the hash. No answer in properly subclassing or perfect overriding seemed to address this. For example,
class MyDict(dict):
def __init__(self, data=None):
if not data:
data = {}
dict.__init__(self, data)
def __getitem__(self, key):
if key == 'b':
print('Found "b"')
return dict.__getitem__(self, key)
shallow_dict = MyDict(data={
'b': 'value'
})
# prints Found "b", as expected
x = shallow_dict['b']
deep_dict = MyDict(data={
'a': {
'b': 'value'
}
})
# prints nothing
x = deep_dict['a']['b']
This happens because when we're accessing ['b']
we're actually accessing a dict
, not MyDict
anymore. So I tried to solve this by copying the content into a new object:
def __getitem__(self, key):
data = dict.__getitem__(self, key)
if key == 'b':
print('Found "b"')
if isinstance(data, dict):
return MyDict(data)
return data
However this solution lead to a new problem while writing content into the hash, because I'm returning a copy and not a reference:
deep_dict['a']['b'] = 'other value'
# prints 'value'
print(deep_dict['a']['b'])
Any suggestions on how to properly maintain the type, since copying had this side effect?
How about your MyDict
just be a proxy
for the dict:
class MyDict(object):
def __init__(self, data={}):
self.data = data
def __getitem__(self, key):
if key == 'b':
print('Found "b"')
return MyDict(self.data.__getitem__(key))
def __setitem__(self, key, value):
return self.data.__setitem__(key, value)
def __repr__(self):
return self.data.__repr__()
# add more __magic__ methods as you wish
shallow_dict = MyDict({
'b': 'value'
})
x = shallow_dict['b']
deep_dict = MyDict({
'a': {
'b': 'value'
}
})
x = deep_dict['a']['b']
# assignment
deep_dict['a']['a'] = {'b': 'here'}
deep_dict['a']['a']['b']
print(deep_dict)
OUTPUT:
Found "b"
Found "b"
Found "b"
{'a': {'b': 'value', 'a': {'b': 'here'}}}
As you can see when you get the self.data inside __getitem__
it just pass the result of self.data.__getitem__
by reference to a new MyDict
object.