Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using super with __getitem__ versus subscript

Tags:

python

super

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?

like image 453
saulspatz Avatar asked Nov 24 '25 19:11

saulspatz


1 Answers

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 by dict.__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
>>>
like image 141
juanpa.arrivillaga Avatar answered Nov 27 '25 09:11

juanpa.arrivillaga