Scott David Daniels
1/1/2008 5:12:00 AM
Steven D'Aprano wrote:
> On Mon, 31 Dec 2007 16:19:11 -0800, Scott David Daniels wrote:
>
>> Steven D'Aprano wrote:
>>> On Mon, 31 Dec 2007 08:03:22 -0800, Scott David Daniels wrote:
>>>> Steven D'Aprano wrote: ...
>>>>> def chain(meth): # A decorator for calling super.
>>>>> def f(self, *args, **kwargs):
>>>>> result = meth(self, *args, **kwargs)
>>>>> S = super(self.__class__, self)
>>>> This line is the problem. The class parameter needs to be the class
>>>> (B in this case) in which the chaining method is defined, not that of
>>>> the object itself.
>>> One minor correction: the class parameter needs to be the class
>>> *itself*, not the class *name* (which would be the string "B").
>> Point taken.
>>
>>> I don't quite understand your description though. What do you mean "the
>>> chaining method is defined"? chain() is defined outside of a class.
>> The class where f (the chaining method) is defined; equivalently, the
>> class in which the @chain is used.
>
> So why doesn't self.__class__ work? That's the class in which @chain is
> used.
OK, here's a simple 3-class example:
class A(object):
def meth(self): print 'A.meth:', self.__class__, '---'
def pn(self): return '<A>'
class B(A):
def meth(self):
super(B, self).meth()
print 'B.meth:', self.__class__, super(B, self).pn()
def pn(self): return '<B>'
class C(B):
def meth(self):
super(C, self).meth()
print 'C.meth:', self.__class__, super(C, self).pn()
def pn(self): return '<C>'
c = C()
c.meth()
# Figure out why it printed what it did.
# If not clear yet, how about this:
for class_ in C, B:
print class_.__name__, super(class_, c).pn()
# And a bigger example (re-using A) to show why we
class B0(A):
def meth(self):
super(B0, self).meth()
print 'B0.meth:', self.__class__, super(B0, self).pn()
def pn(self): return '<B0>'
class B1(B0):
def meth(self):
super(B1, self).meth()
print 'B1.meth:', self.__class__, super(B1, self).pn()
def pn(self): return '<B1>'
class B2(B0):
def meth(self):
super(B2, self).meth()
print 'B2.meth:', self.__class__, super(B2, self).pn()
def pn(self): return '<B2>'
class C1(B1, B2):
def meth(self):
super(C1, self).meth()
print 'C1.meth:', self.__class__, super(C1, self).pn()
def pn(self): return '<C1>'
class D1(C1):
def meth(self):
super(D1, self).meth()
print 'D1.meth:', self.__class__, super(D1, self).pn()
def pn(self): return '<D1>'
d = D1()
d.meth()
# Figure out why it printed what it did.
for class_ in D1, C1, B1, B2, B0:
print class_.__name__, super(class_, d).pn()
# Now (after much cogitation) might that do it?
# finally, just a fillip, predict this before you run it:
class E(D1, C):
def meth(self):
super(E, self).meth()
print 'E.meth:', self.__class__, super(E, self).pn()
def pn(self): return '<E>'
e = E()
e.meth()
for class_ in E, D1, C1, B1, B2, B0, C, B:
print class_.__name__, super(class_, e).pn()
> I can clearly see that it doesn't work, I just don't understand why. I'd
> be inclined to chalk it up to super() being a mysterious black box that
> makes no sense *wink* ....
super (and mro) work to get to all the superclasses in an order that
produces subtypes before their supertypes. The diamond inheritance
examples "show" why its needed.
-Scott