M
Mike Krell
I'm reading Alex Martelli's "Nutshell" second edition. In the section
called "Cooperative superclass method calling", he presents a diamond
inheritance hierachy:
class A(object):
def met(self):
print "A.met"
class B(A):
def met(self):
print "B.met"
A.met(self)
class C(A):
def met(self):
print "C.met"
A.met(self)
class D(B,C):
def met(self):
print "D.met"
B.met(self)
C.met(self)
D().met() # essentially "D B A C A"
Martelli says "In this code, when we call D().met(), A.met ends up being
called twice. How can we ensure that each ancestor's implementation of
the method is called once, and only once? The solution is to use
built-in type super. super(aclass, obj), which returns a special
superobject of object obj. When we look up an attribute (e.g., a method)
in this superobject, the lookup begins after class aclass in obj's
MRO. We can therefore rewrite the previous code as:
class A(object):
def met(self):
print "A.met"
class B(A):
def met(self):
print "B.met"
super(B, self).met()
class C(A):
def met(self):
print "C.met"
super(C, self).met()
class D(B,C):
def met(self):
print "D.met"
super(D, self).met()
D().met() # essentially "D B C A"
Now, D().met() results in exactly one call to each class's version of
met."
I see that this is true, but I am confused by the explanation (the bit
about truncated lookup in the class's MRO). In particular:
1. The super() call in D somehow invokes both parent class methods
instead of stopping when the method is resolved in B. This has
nothing to do with truncated lookup per se. Why isn't the output "D
B A"?
2. If I understand correctly, B's MRO is (B, A) and super(B, self) would
have an MRO of (A). Similarly for C. So it seems that by the above
explanation, A.met() would still be invoked twice (assuming both
B.met() and C.met() are invoked).
I guess I can just take it on faith that super() invokes everything once
and only once, but I'd rather understand how. Can someone point me to a
more complete description of super()'s semantics and how they work?
BTW, the official docs are even worse in this regard. AFAICT, they
essentially say that super() returns a superclass with no discussion of
diamond inheritance or any hint of how the semantics of super(B,
self).met() would be any different than those of A.met(self).
This seems like very important functionality to be documented in the
official docs so poorly.
Mike
called "Cooperative superclass method calling", he presents a diamond
inheritance hierachy:
class A(object):
def met(self):
print "A.met"
class B(A):
def met(self):
print "B.met"
A.met(self)
class C(A):
def met(self):
print "C.met"
A.met(self)
class D(B,C):
def met(self):
print "D.met"
B.met(self)
C.met(self)
D().met() # essentially "D B A C A"
Martelli says "In this code, when we call D().met(), A.met ends up being
called twice. How can we ensure that each ancestor's implementation of
the method is called once, and only once? The solution is to use
built-in type super. super(aclass, obj), which returns a special
superobject of object obj. When we look up an attribute (e.g., a method)
in this superobject, the lookup begins after class aclass in obj's
MRO. We can therefore rewrite the previous code as:
class A(object):
def met(self):
print "A.met"
class B(A):
def met(self):
print "B.met"
super(B, self).met()
class C(A):
def met(self):
print "C.met"
super(C, self).met()
class D(B,C):
def met(self):
print "D.met"
super(D, self).met()
D().met() # essentially "D B C A"
Now, D().met() results in exactly one call to each class's version of
met."
I see that this is true, but I am confused by the explanation (the bit
about truncated lookup in the class's MRO). In particular:
1. The super() call in D somehow invokes both parent class methods
instead of stopping when the method is resolved in B. This has
nothing to do with truncated lookup per se. Why isn't the output "D
B A"?
2. If I understand correctly, B's MRO is (B, A) and super(B, self) would
have an MRO of (A). Similarly for C. So it seems that by the above
explanation, A.met() would still be invoked twice (assuming both
B.met() and C.met() are invoked).
I guess I can just take it on faith that super() invokes everything once
and only once, but I'd rather understand how. Can someone point me to a
more complete description of super()'s semantics and how they work?
BTW, the official docs are even worse in this regard. AFAICT, they
essentially say that super() returns a superclass with no discussion of
diamond inheritance or any hint of how the semantics of super(B,
self).met() would be any different than those of A.met(self).
This seems like very important functionality to be documented in the
official docs so poorly.
Mike