[Python-ideas] OrderedCounter and OrderedDefaultDict

Chris Angelico rosuav at gmail.com
Wed Oct 21 00:50:21 CEST 2015


On Wed, Oct 21, 2015 at 8:56 AM, Carl Meyer <carl at oddbird.net> wrote:
> I think you missed her real point, which applies both to Python and
> Ruby. In her presentation, it's obscured a bit by too much discussion of
> "one side or the other" code duplication (which can be "solved" with
> multiple inheritance). It takes her a couple minutes more to get to the
> real point, which starts at the slide "inheritance is for
> specialization, not for sharing code."

Sure, but a dictionary with a default handler _is_ a form of
specialization - as is a dictionary that preserves order. Both of them
behave absolutely identically to a regular dict when you set
something, retrieve it, iterate over them, etc, etc, etc. She
recommends a massive superclass that's capable of any form of
injection; using inheritance allows the dict type to be broadly
unaware of the modified dictionaries that exist.

Suppose I write a SortedDict that behaves exactly the way any other
dictionary does, but when you iterate over its keys, you get them in
order. I should be able to do this without tampering with the original
dict type. In the composition model, I would need to appeal for an
"IterationOrder" feature to be added to the base dict; using
inheritance, it's as simple as:

class SortedDict(dict):
    def __iter__(self):
        yield from sorted(self.keys())

To me, this is the biggest benefit of inheritance: you do NOT have to
predict what someone might want to do. I can subclass someone else's
object and change how it works.

> One symptom of the problem is that using multiple inheritance this way
> doesn't scale: the number of leaf subclasses you need grows
> geometrically with the number of behavior knobs. Composition with
> strategy objects doesn't have this issue.

Sure it does... but nobody needs to know about _all_ the leaf
subclasses. How many subclasses of object are there in Python?

>>> len(object.__subclasses__())
122

And that in a bare interactive Py3, without importing anything fancy.
('import decimal' raises that to 159, for instance.)

Composition has its place, don't get me wrong. But inheritance isn't
the attractive nuisance she makes it out to be. It works just fine.

ChrisA


More information about the Python-ideas mailing list