Kevin Smith wrote:
I like the idea of the super() function, but it doesn't seem to solve the problem that I'm trying to fix. I don't like hard-coding in calls to super classes using their names:You perhaps already know that super() searches the method resolution order (list of superclasses) to find a given class's superclass. However, in cases involving multiple inheritance (and specifically when subclassing two classes that have common ancestors) it's necessary to "flatten out" the inheritance tree.
class A(object): def go(self): ...
class B(A): def go(self): ... A.go(self)
I don't like this because if I ever change the name of 'A', I have to go through all of the methods and change the names there too. super() has the same problem, but I'm not sure why. It seems like I should be able to do:
class B(A): def go(self): ... super(self).go()
I can create a super() that does this as follows:
_super = super def super(obj, cls=None): if cls is None: return _super(type(obj), obj) return super(cls, obj)
I guess I'm just not sure why it wasn't done that way in the first place.
The reason that super() takes a class as argument is because the superclass depends *not* on the class in which the method is defined, but on *the class of the instance calling the method*.
If we take the example from pp 89-90 of Python in a Nutshell you might understand. Consider these definitions:
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 = D() d.met()
Unfortunately this prints out
D.met B.met A.met C.met A.met
In other words, A.met is called by both its subclasses, which is usually not quite what you want. If we change the code to
class A(object): # mro: A, object def met(self): print 'A.met'
class B(A): # mro: B, A, object def met(self): print 'B.met' super(B, self).met()
class C(A): # mro: C, A, object def met(self): print 'C.met' super(C, self).met()
class D(B,C): # mro: D, B, C, A, object def met(self): print 'D.met' super(D, self).met()
d = D() d.met()
This does indeed print
D.met B.met C.met A.met
Why? The superobject (the object returned by super) has an mro which begins AFTER the first argument to super. This has the happy effect of changing the mro according to the class of self - super(X, self) is superobject, effectively an instance of a class distinguishable from self.__class__ only by the fact that its mro is shorter, losing everything up to and including X.
Does this help at all? This is quite a subtle point, but it will repay study with an understanding of exactly how you can linearize your diamond-shaped inheritance graphs. Very pythonic ...
regards Steve -- Meet the Python developers and your c.l.py favorites March 23-25 Come to PyCon DC 2005 http://www.pycon.org/ Steve Holden http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list