Reputation: 339
I am working through the O Reilly Python Cookbook and have been struggling with the below code. It is to with calling a method on a parent class using super()
:
class Proxy:
def __init__(self, obj):
self._obj = obj
# Delegate attribute lookup to internal obj
def __getattr__(self, name):
return getattr(self._obj, name)
# Delegate attribute assignment
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value) # Call original __setattr__
else:
setattr(self._obj, name, value)
if __name__ == '__main__':
class A:
def __init__(self, x):
self.x = x
def spam(self):
print('A.spam')
a = A(42)
p = Proxy(a)
print(p.x)
print(p.spam())
p.x = 37
print('Should be 37:', p.x)
print('Should be 37:', a.x)
The book states:
In this code the implementation of
__setatrr__()
includes a name check. If the name starts with an underscore it invokes the original implementation of__setattr__()
usingsuper()
. Otherwise, it delegates to the internally held objectself._obj
.
I am confused. How does super()
work then if there is no explicit base class listed?
What exactly then is super()
referring to?
Upvotes: 0
Views: 971
Reputation: 531165
There is always a base class; with none explicitly mentioned, Proxy
inherits directly from object
.
Each class defines a method-resolution order, determined recursively by its base class(es) and its ancestors. When super()
gets called, it resolves to a "proxy" of the next class in the MRO of self
, whether or not that class appears in the MRO of the class you are currently defining.
Consider the following classes:
class A:
def foo(self):
print("A.foo")
class B(A):
def foo(self):
super().foo()
print("B.foo")
class C(A):
def foo(self):
super().foo()
print("C.foo")
class D(C):
def foo(self):
super().foo()
print("D.foo")
class E(B,D):
def foo(self):
super().foo()
print("E.foo")
e = E()
The MRO of E
is [E, B, D, C, A, object]
. When you call e.foo()
, you start a chain of calls in MRO order. In particular, the call to super
in B.foo
does not invoke A.foo
, but D.foo
, a method in a class B
knows nothing about, as D
is not an ancestor of B
. But both B
and D
are ancestors of E
, which is what matters.
Upvotes: 3