Chanelling Guido - dict subclasses

Gregory Ewing greg.ewing at canterbury.ac.nz
Wed Jan 15 23:17:28 EST 2014


Daniel da Silva wrote:

> Just to be pedantic, this /is/ a violation of the Liskov Substution 
> Principle. According to Wikipedia, the principle states:
> 
>      if S is a subtype <http://en.wikipedia.org/wiki/Subtype> of T, then
>     objects of type <http://en.wikipedia.org/wiki/Datatype> T may be
>     replaced with objects of type S (i.e., objects of type S may
>     be /substituted/ for objects of type T) without altering any of the
>     desirable properties of that program

Something everyone seems to miss when they quote the LSP
is that what the "desirable properties of the program" are
*depends on the program*.

Whenever you create a subclass, there is always *some*
difference between the behaviour of the subclass and
the base class, otherwise there would be no point in
having the subclass. Whether that difference has any
bad consequences for the program depends on what the
program does with the objects.

So you can't just look at S and T in isolation and
decide whether they satisfy the LSP or not. You need
to consider them in context.

In Python, there's a special problem with subclassing
dicts in particular: some of the core interpreter code
assumes a plain dict and bypasses the lookup of
__getitem__ and __setitem__, going straight to the
C-level implementations. If you tried to use a dict
subclass in that context that overrode those methods,
your overridden versions wouldn't get called.

But if you never use your dict subclass in that way,
there is no problem. Or if you don't override those
particular methods, there's no problem either.

If you're giving advice to someone who isn't aware
of all the fine details, "don't subclass dict" is
probably the safest thing to say. But there are
legitimate use cases for it if you know what you're
doing.

The other issue is that people are often tempted to
subclass dict in order to implement what isn't really
a dict at all, but just a custom mapping type. The
downside to that is that you end up inheriting a
bunch of dict-specific methods that don't really
make sense for your type. In that case it's usually
better to start with a fresh class that *uses* a
dict as part of its implementation, and only
exposes the methods that are really needed.

-- 
Greg



More information about the Python-list mailing list