How to properly override the default factory of defaultdict?

Chris Angelico rosuav at gmail.com
Fri Feb 19 21:19:14 EST 2016


On Sat, Feb 20, 2016 at 11:24 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>> Look like inheriting from defaultdict is easier. I don't even  have to
>> override the constructor as suggested by Chris Angelico above. Thanks.
>
> True, although there's a faint code smell as this technically violates
> the Liskov Substitution Principle; the default_factory attribute on
> defaultdict instances is expected to be a function of zero arguments,
> not one.

My suggestion was a minimal change against his own code, but really,
the right way to do it is to not subclass defaultdict at all - just
subclass dict and define __missing__. Then there's no violation of
LSP, and probably no super() call either.

And the correct way to use super() is with no arguments and Python 3.
Much less fiddling around, no repetition of the class name, and you're
not depending on a global name lookup that might fail:

Python 2.7:

>>> class Foo(object):
...  def method(self): print("Base method")
...
>>> class Bar(Foo):
...  def method(self):
...   super(Bar,self).method()
...   print("Derived method")
...
>>> b = Bar()
>>> del Bar
>>> b.method()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in method
NameError: global name 'Bar' is not defined

Python 3.6:
>>> class Foo(object):
...  def method(self): print("Base method")
...
>>> class Bar(Foo):
...  def method(self):
...   super().method()
...   print("Derived method")
...
>>> b = Bar()
>>> del Bar
>>> b.method()
Base method
Derived method

Yes, that's a little contrived. But imagine the mess if you use a
class decorator that returns a function, or accidentally reuse a name
at the interactive prompt, or something. Needing to look something up
just to find your own parent seems unnecessary.

(That said, though, we depend on a name lookup to perform a recursive
function call, and that's a lot more likely to be rebound than a
class. But the no-arg super is still better for the other reasons.)

ChrisA


More information about the Python-list mailing list