Michael
Michael

Reputation: 2367

Why in `super(A, self)` does the object come before the `self`?

I am wondering why the syntax for calling the super classes' constructors has the Child object passed as an argument before the self, and what purpose those arguments serve as to the goal of inheriting the methods of the parent class.

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

I've read the following posts, but in either have I found the reasoning for this:

  1. The 'super' docs

  2. What does 'super' do in Python?

  3. In this post I've found this quote:

    super(class, subclass).method returned a bound method, not an unbound one

    but still could not get my head around the meaning of this syntax.

Appreciate an elaboration of this syntax.

Upvotes: 1

Views: 316

Answers (1)

MisterMiyagi
MisterMiyagi

Reputation: 50116

The order of super arguments reflects Python's idea of unbound and bound methods/descriptors. In short, the second argument is optional and thus must come after the required first argument.

Built-in Functions: super([type[, object-or-type]])

[...]

If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

This reflects how a method call self.method() is equivalent to Class.method(self), i.e. the order of operands is Class then self.*


Python methods/descriptors come in two flavours: unbound on their defining class, and bound on their instance.*

>>> class Base:
...     def method(self): print('called Base method')
...
>>> Base.method     # unbound method
<function __main__.Base.method(self)>
>>> Base().method   # bound method
<bound method Base.method of <__main__.Base object at 0x10dd0e910>>
>>> Base().method()
called Base method

A bound descriptor is created by taking an unbound descriptor and binding it to an instance. This is encoded and implemented in the descriptor protocol.

>>> instance = Base()
>>> unbound = Base.method
>>> unbound.__get__(instance)
<bound method Base.method of <__main__.Base object at 0x10dd14510>>
>>> unbound.__get__(instance)()
called Base method

The super type is by default unbound. Binding it via the descriptor protocol or by passing an instance is equivalent.

>>> class Child(Base): ...
>>> instance = Child()
>>> super(Child, instance)
<super: __main__.Child, <__main__.Child at 0x10dcda9d0>>
>>> super(Child).__get__(instance)
<super: __main__.Child, <__main__.Child at 0x10dcda9d0>>

In either case, the class must be passed first before the instance.


From the python-dev archive:

Add 'super', another new object type with magical properties.

super(type) -> unbound super object

super(type, obj) -> bound super object; requires isinstance(obj, type)

Typical use to call a cooperative superclass method:

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg);

* This description glosses over the finer details of the descriptor protocol. For example, a method/descriptor can be bound to a class as well.

Upvotes: 1

Related Questions