0

Say I have this sample code I'm writing for a Python lesson I'm holding:

class Enum(dict):
  def __init__(self, *values):
    values = {mnemo: num
      for num, mnemo in enumerate(values)}
    dict.__init__(self, values) # ← this
  def __getattr__(self, name):
    return self[name]

This seems to work as expected, at least on a shallow method, but what I see most of the time on the literature on the Internet is:

I guess especially the latter is more DRY, but super() is going to be trickier to explain once I start throwing in multiple inheritance. I want to make sure, then, that there are no nasty gotchas in there that other people will then stumble upon.

Community
  • 1
  • 1
badp
  • 11,409
  • 3
  • 61
  • 89
  • If you introduce super, do it properly. One cannot use it well without understanding the concept of the MRO. See [Python's super() considered super!](http://rhettinger.wordpress.com/2011/05/26/super-considered-super/). –  Mar 29 '12 at 13:24
  • @delnan I was actually considering not introducing it at all :P – badp Mar 29 '12 at 13:29

1 Answers1

4
  1. I don't see why you should generally avoid to derive from built-in types. It was considered an improvement that the arrival of new-style classes enabled to do this, and even before this the standard library provided the UserDict and UserList classes to derive from. Of course you have to evaluate in every specific case whether inheritance or composition is what you need, but that's how in always is in OOP -- nothing special about built-in types here.

  2. I wouldn't recommend super() in the example. It is only useful if all cooperating methods have the same signature, or at least cooperating signatures. For single inheritance and "diamond-free" multiple inheritance, explicitly calling base-class methods is fine in my opinion. If you want to get things right in multiple inheritance with diamonds, you are forced to use super(), but you have to design your methods carefully, see Raymond Hettinger's "Python's super() considered super!"

    It is generally safe to use super() in cases where all involved methods have exactly the same signature, including methods likes __getattr__() and __setattr__().

  3. Your example class is a rather questionable implementation of an Enum type, but not for any of the reasons you mentioned in your post. It mixes up two namespaces: The namespace of the attributes of dict and the enumeration entries. Try Enum("clear", "update") to see what I mean. In this particular case, the follwing implementation would be much better:

    class Enum(object):
        def __init__(self, *values):
            vars(self).update({mnemo: num for num, mnemo in enumerate(values)})
    

    This adds the enumeration entries as attributes to a standard instance without deriving from dict. Every custom class instance brings its own dictionary anyway, namely __dict__.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 1
    Re: 1. There's no guarantee overriden methods are called by builtin non-overriden methods. For instance, if you inherit from `dict` and override `__getitem__` but not `get`, the latter may bypass your override for the former. –  Mar 29 '12 at 13:47