9

I am reading Fluent Python and trying to get a deeper understanding of dictionaries.

So when I run the below, the results are easy to understand in that both get() and dunder getitem() return the same result

sample = {'a':1, 'b':2}
print(sample.__getitem__('a')) # 1
print(sample.get('a')) # 1

When I subclass dict with get(), I get a working instance

class MyDict(dict):
    def __missing__(self, key):
        return 0

    def get(self, key):
        return self[key]

d = MyDict(sample)
print(d['a']) # 1
print(d['c']) # 0

Now if I replace get() with dunder getitem() I get an error and I am unsure why.

class MyDict2(dict):
    def __missing__(self, key):
        return 0

    def __getitem__(self, key):
        return self[key]

d = MyDict2(sample)
print(d['a'])
print(d['c'])

error

RecursionError: maximum recursion depth exceeded while calling a Python object

So the question is, what is the difference between get and dunder getitem in this situation and why does this cause a recursion error?

yoyoyoyo123
  • 2,362
  • 2
  • 22
  • 36

2 Answers2

8

in

def __getitem__(self, key):
    return self[key]

self[key] calls the lowest-level __getitem__ which calls self[key] ... infinite recursion.

In:

def get(self, key):
    return self[key]

self[key] calls the lowest-level __getitem__ as well but from the dict class, so it doesn't recurse: it works (you just overloaded the get method, that's all)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
5

That is because self[key] in MyDict2.__getitem__(key) is equivalent to (i.e., calls) self.__getitem__(key) => infinite recursion.

AGN Gazer
  • 8,025
  • 2
  • 27
  • 45