How does `super()` work in Python, and why is the zero-argument form preferred over `super(ClassName, self)`?
`super()` returns a proxy that delegates method calls to the next class in the MRO, not necessarily the direct parent. The zero-argument form `super()` (Python 3) is preferred because it uses a compiler-injected `__class__` cell, which correctly tracks the defining class even under multiple inheritance — avoiding the brittle repetition of the class name.
How to think about it
What’s really being tested
The interviewer wants to see whether you understand that super() is not just a synonym for “call the parent.” It’s about the Method Resolution Order (MRO) — the linearised list of classes Python uses to look up methods. That distinction is invisible in single inheritance but becomes critical the moment you have a diamond-shaped class hierarchy.
Single inheritance — the easy case
Start here because it’s intuitive. super().__init__() just calls Animal.__init__ from inside Dog:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # delegates to Animal.__init__
self.breed = breed
This works and everyone understands it. The interesting case is multiple inheritance.
Multiple inheritance — why “next in MRO” matters
When class D inherits from both B and C, and both inherit from A, Python needs to ensure A.__init__ is called exactly once. The MRO for D is [D, B, C, A, object]. Each class’s super() call walks to the next entry in that list — not its own parent.
Without super() in B and C, C.setup or A.setup would be skipped entirely, or A.setup would run twice. super() makes cooperative inheritance possible.
Zero-argument vs explicit form
# Python 3 — preferred
super().__init__(name)
# Python 2 / explicit form — error-prone
super(Dog, self).__init__(name)
The explicit form hardcodes the class name. If you rename Dog, copy the method to a subclass, or refactor the hierarchy, that hardcoded name breaks silently or raises a confusing TypeError at runtime. The zero-argument form uses __class__, a read-only closure variable injected by the compiler at method definition time. It always refers to the class that textually defines the method, regardless of what self is at runtime.