Reputation: 2367
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.
Upvotes: 1
Views: 316
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.
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