47

I am trying to understand when and how to use super() in Python correctly (either 2.7.x or 3.x)

on >>> help(super) the interpreter tells me how to call it:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)

I understand that in Python3.x it's now possible to juse use super() within a class definition, but I don't understand why super(obj) is not possible. Or super(self) within a class definition.

I know there must be a reason for it, but I can't find it. To me those lines are equivalent to super(obj.__class__, obj) or super(self.__class__, self) and those would work right?

I would think that just typing super(obj) would be a nice shortcut even in Python 3.x.

Gabriel
  • 1,078
  • 1
  • 8
  • 15
  • I was going to say that it'd cause ambiguity when you call `super` on a metaclass, but then I realized that that ambiguity also exists with the 2-argument form. Now I'm not sure. – user2357112 Jul 07 '13 at 06:46

2 Answers2

68

The two-argument form is only needed in Python 2. The reason is that self.__class__ always refers to the "leaf" class in the inheritance tree -- that is, the most specific class of the object -- but when you call super you need to tell it which implementation is currently being invoked, so it can invoke the next one in the inheritance tree.

Suppose you have:

class A(object):
   def foo(self):
      pass

class B(A):
   def foo(self):
      super(self.__class__, self).foo()

class C(B):
   def foo(self):
      super(self.__class__, self).foo()

c = C()

Note that c.__class__ is C, always. Now think about what happens if you call c.foo().

When you call super(self.__class__, self) in a method of C, it will be like calling super(C, self), which means "call the version of this method inherited by C". That will call B.foo, which is fine. But when you call super(self.__class__, self) from B, it's still like calling super(C, self), because it's the same self, so self.__class__ is still C. The result is that the call in B will again call B.foo and an infinite recursion occurs.

Of course, what you really want is to be able to call super(classThatDefinedTheImplementationThatIsCurrentlyExecuting, self), and that is effectively what the Python 3 super() does.

In Python 3, you can just do super().foo() and it does the right thing. It's not clear to me what you mean about super(self) being a shortcut. In Python 2, it doesn't work for the reason I described above. In Python 3, it would be a "longcut" because you can just use plain super() instead.

The super(type) and super(type1, type2) uses might still be needed occasionally in Python 3, but those were always more esoteric usages for unusual situations.

zanetu
  • 3,740
  • 1
  • 21
  • 17
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • 2
    A coworker once refactored a piece of a method that called `super` into a separate method in another class, so the code ended up saying `super(SomeOtherClass, some_obj).method(...)` That worked perfectly, but it looked just like a bug to anyone who read the code. Although this could have been (and ended up being) expressed better, the two-argument form of `super` can still be useful in some edge cases. – user4815162342 Jul 07 '13 at 08:17
  • 2
    The first 4 lines of your explanation made me understand everything. Thank you for the example as well. That was the missing piece that I was trying to understand. – Gabriel Jul 09 '13 at 03:14
  • We keep referring to an 'esoteric' or 'edge' case. Is this simply when double inheritance requires we call two separate `__init__()` functions when overriding `__init__()` in the leaf class? – Chris Conlan Sep 08 '17 at 22:24
  • 1
    @ChrisConlan: The cases being referred to there are cases where you are calling super with two types rather than a type and an instance. This would be for instance, if you want to call a classmethod rather than instance method. See [this question](https://stackoverflow.com/questions/7466463/why-and-how-to-use-pythons-supertype1-type2). – BrenBarn Sep 09 '17 at 01:54
12

Trying a short answer:

self.__class__ is always the actual ("sub-most") class of your object instance – not necessarily the wanted class, which implements the function!

Replace super(self.__class__, self) with super(__class__, self) and you are right within a method definition in Python 3, because Python 3 provides the magic cell variable __class__ for the implementing class.

And simply super() with zero arguments is already the shortcut for super(__class__, self) in Python 3. See PEP3135.

Python 2 neither knows __class__ nor the zero-argument shortcut super().

kxr
  • 4,841
  • 1
  • 49
  • 32
  • 1
    super() (no-args) is a little surprising. The PEP says its not a keyword, so its a little unclear exactly how it finds __class__ and self. – user48956 May 13 '20 at 22:19
  • 1
    @user48956 `super()` is equivalent to `super(__class__, )`. Wherever the call to `super()` is, look at the method (function defined directly within a class body) it is defined in, and substitute `__class__` with that class, and `` with the first argument of that method. – pallgeuer May 22 '20 at 09:27
  • What tripped me up (making me Google this question) is that if you define a local function that calls `super()` inside a method of class A, but make that local function a method of another class B, then `super()` will resolve `__class__` to be A, not dynamically resolve it at execution time to be B. – pallgeuer May 22 '20 at 09:30