13

I have a class hierarchy A <- B <- C, in B, I need some processing in the constructor, so I came up with this code from this post: Understanding Python super() with __init__() methods

#!/usr/bin/python

class A(object):
    def __init__(self, v, v2):
        self.v = v
        self.v2 = v2

class B(A):
    def __init__(self, v, v2):
        # Do some processing
        super(self.__class__, self).__init__(v, v2)

class C(B):
    def hello():
        print v, v2


b = B(3, 5)
print b.v
print b.v2

c = C(1,2)
print c

However, I have an runtime error from maximum recursion exceeded

  File "evenmore.py", line 12, in __init__
    super(self.__class__, self).__init__(v, v2)
RuntimeError: maximum recursion depth exceeded while calling a Python object

What might be wrong?

Community
  • 1
  • 1
prosseek
  • 182,215
  • 215
  • 566
  • 871

2 Answers2

9

First thing to consider: C inherits constructor from B (because it's not defined in C).

Second thing to consider: self.__class__ in __init__ invocation in C class is C, not B.

Let's analyze:

  • C().__init__ calls super(self.__class__, self).__init__(v, v2) which is resolved to super(C, self).__init__(v, v2) which means B.__init__(self, v, v2).
  • First argument passed to B.__init__ has a type C. super(self.__class__, self).__init__(v, v2) is again resolved to B.__init__(self, v, v2).
  • And again, and again, and again. And there is your infinite recursion.
Łukasz Rogalski
  • 22,092
  • 8
  • 59
  • 93
2

Giving the first parameter of super as the class name solves this issue.

class B(A):
    def __init__(self, v, v2):
        # Do some processing
        super(B, self).__init__(v, v2)
prosseek
  • 182,215
  • 215
  • 566
  • 871
  • It should be clear why; `self.__class__` is always the concrete class, not the name of whatever class you're in in the MRO. In fact, the second answer in the post you link to goes into exactly this in great detail. – Daniel Roseman Sep 28 '15 at 20:28