Search code examples
pythonpython-3.4defaultdict

For Python 3.4: Why do I get a KeyError when I subclass defaultdict, override __init__, and define default_factory in the subclass’s scope?


The following code does not raise a KeyError.

from collections import defaultdict


class A(defaultdict):

    def __init__(self):
        self.default_factory = int


a = A()
print(a[42])  # out: 0

The following code raises a KeyError.

from collections import defaultdict


class A(defaultdict):

    def __init__(self):
        pass


class B(A):

    default_factory = int


b = B()
print(a[42])  # out: KeyError: 42

In my flawed imagination, the second example plays out like this:

1) call the parent A class's __init__ method at the construction of the b object

2) call the defaultdict class's __missing__ method at reference to non-existent key 42

3) refer to the b object's default_factory attribute only to find no such attribute

4) refer to the B class's attributes to find default_factory defined as int

5) return int back to the defaultdict class's __missing__ method

6) call default_factory (which is int) which returns a 0 by default to __missing__

7) define the b object's key 42 value as 0

8) print 0

Maybe I'm wrong about step 2? Which of my assumptions are incorrect or what is the critical difference between my first and second examples?


Solution

  • defaultdict is not a Python class, it is a C type. As such it doesn't support attribute lookups on the class, it only supports setting the default_factory on the instance.

    In other words, step 4 never takes place.

    Step 2 does take place, but this step is implemented in C as using:

    PyObject *factory = dd->default_factory;
    

    and default_factory is defined as a member of the instance only. See the defaultdict C source.