Builtn super() function. How to use it with multiple inheritance? And why should I use it at all?

Ian Kelly ian.g.kelly at gmail.com
Sat Jul 31 14:16:07 EDT 2010


On Sat, Jul 31, 2010 at 4:22 AM, Steven D'Aprano
<steve at remove-this-cybersource.com.au> wrote:
> On Fri, 30 Jul 2010 21:40:21 -0600, Ian Kelly wrote:
>
>> I have to chime in and agree that the name "super" is problematic. I'm
>> reading this thread with a sense of alarm because I apparently never
>> read the super() documentation too closely (why would I?  "Oh, it just
>> accesses an attribute from a superclass.  Moving on.") and have been
>> writing code for the past four years under the impression that super()
>> will always refer to a superclass of the current class.
>
> In Python 2.x, super() doesn't know what the current class is. You have
> to explicitly tell it. If you tell it a lie, surprising things will
> happen.
>
> Assuming you accurately tell it the current class, can you give an
> example where super() doesn't refer to a superclass of the current class?

Brian gave a good example, so I refer you to that.

>> On a tangent, is it just me, or is the super() documentation incorrect,
>> or at least unclear?  Quoting from the first two paragraphs:
>
> Yes, it's a bit unclear, because it's a complex function for dealing with
> a complicated situation. But if you have single inheritance, it's simple.
> Anywhere you would write
>
> class C(B):
>    def method(self, *args):
>        B.method(*args)
>
> you can write
>
> class C(B):
>    def method(self, *args):
>        super(C, self).method(*args)
>
>
> and it will Just Work.

Until somebody else comes along and creates class E that inherits from
both C and D and also uses super(), and now suddenly the super() call
in C becomes equivalent to "D.method(*args)" instead for instances of
E, potentially with unexpected results.  Or worse, E.method
incorrectly calls both C.method and D.method explicitly, and now
D.method gets invoked twice, once implicitly from C.method, and once
explicitly from E.method.

I realize that it is the responsibility of the person writing class E
to make sure they're working with class C correctly, but in order for
them to do that, ultimately every method in class C should be
documented as to whether it calls super() or not, and if so whether it
is designed only for single inheritance or with the MRO in mind.  That
really shouldn't be necessary, and in my current view from a
maintenance perspective, best practice is to only use super() in the
multiple-inheritance scenarios it was specifically designed for

>> super(type[, object-or-type])
>>
>>     Return a proxy object that delegates method calls to a parent or
>> sibling class of type.
>
> I think that the bit about sibling class refers to super(type, type2)
> calls, rather than the super(type, instance) calls which I've been
> discussing. I've never needed, and don't understand, the two type version
> of super(), so I can't comment on it.

I understand the two-type version works the same way, but is intended
for class methods, like so:

class A(object):
  @classmethod
  def f(cls, *args):
    print "A.f"

class B(A):
  @classmethod
  def f(cls, *args):
    print "B.f"
    return super(B, cls).f(*args)

class C(A):
  @classmethod
  def f(cls, *args):
    print "C.f"
    return super(C, cls).f(*args)

class D(B, C):
  @classmethod
  def f(cls, *args):
    print "D.f"
    return super(D, cls).f(*args)

Cheers,
Ian



More information about the Python-list mailing list