I'm writing a dict
which only has tuples of positive integers as keys. If the key is unknown and one of the elements of the tuple is 1
, lookup should return a default value of 0
. Any other unknown key should raise KeyError
.
This works fine:
class zeroDict(dict):
'''
If key not in dict and an element of the tuple is
a 1, impute the value 0.
'''
def __init__self():
super().__init__()
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
if 1 in key:
return 0
else:
raise
This does not:
class zDict(dict):
'''
If key not in dict and an element of the tuple is
a 1, impute the value 0.
'''
def __init__self():
super().__init__()
def __getitem__(self, key):
try:
return super()[key]
except KeyError:
if 1 in key:
return 0
else:
raise
When I try to read a value from zDict
I get TypeError: 'super' object is not subscriptable
.
The only difference between the implementations is that zeroDict
says
return super().__getitem__(key)
and zDict
says
return super()[key]
However, help(dict.__getitem__)
prints
__getitem__(...)
x.__getitem__(y) <==> x[y]
which seems to say that the two statements are equivalent. What is going on here?
As others have explained, the reason that super()
is not working here is because it returns a super object, which is a proxy object that handles dispatching dotted attribute access to the next class in the method resolution order.
That being said, you shouldn't be overriding __getitem__
here, the python data-model provides something just for this case, it's the __missing__
method:
object.__missing__(self, key)
implement
self[key]
for dict subclasses when key is not in the dictionary.Called bydict.__getitem__()
So, do something like this:
class ZeroDict(dict):
def __missing__(self, key):
if 0 in key:
return 0
else:
raise KeyError(key)
And a demonstration:
>>> class ZeroDict(dict):
... def __missing__(self, key):
... if 0 in key:
... return 0
... else:
... raise KeyError(key)
...
>>> d = ZeroDict()
>>> d[(1, 0)] = 'foo'
>>> d
{(1, 0): 'foo'}
>>> d[1, 0]
'foo'
>>> d[1, 1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __missing__
KeyError: (1, 1)
>>> d[0, 1]
0
>>>