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?
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.