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:
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.
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.
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.