A colleague of mine wrote code analogous to the following today, asked me to have a look, and it took me a while to spot the mistake:
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
super(B).__init__()
b = B()
The problem here is that there's no self
parameter to super()
in B
's constructor. What surprised me is that absolutely nothing happens in this case, i.e. no error, nothing. What does the super
object created by super(B)
contain? As an object, it clearly has a constructor, so that's what gets called, but how is that object related to B
? In particular, why is this valid code and doesn't throw an exception somewhere? Is super(B)
an object with some actual use and what would that be?
The only thing that causes all these ambiguities is that "why
obj = super(B).__init__()
works?". That's becausesuper(B).__self_class__
returnsNone
and in that case you're calling theNone
objects'__init__
like following which returns None:Regarding the rest of the cases, you can simply check the difference by calling the
super
's essential attributes in both cases:For the rest of the things I recommend you to read the documentation thoroughly. https://docs.python.org/3/library/functions.html#super and this article by Raymond Hettinger https://rhettinger.wordpress.com/2011/05/26/super-considered-super/.
Moreover, If you want to know why
super(B)
doesn't work outside of the class and generally why calling thesuper()
without any argument works inside a class you can read This comprehensive answer by Martijn https://stackoverflow.com/a/19609168/2867928.A short description of the solution:
As mentioned in the comments by @Nathan Vērzemnieks you need to call the initializer once to get the
super()
object work. The reason is laid behind the magic of newsuper
object that is explained in aforementioned links.The confusion here comes from the fact that (in a class definition context)
super()
gives a boundsuper
object which then delegates__init__
to its__self_class__
, whilesuper(B)
creates an unboundsuper
object which, because its__self_class__
isNone
, does not delegate.So when you call
super(B).__init__()
, it creates an unboundsuper
but then immediately calls__init__
on it; that, because of the magic described in the various links in this other answer, binds that unboundsuper
. There are no references to it, so it disappears, but that's what's happening under the hood.