using super

Basilisk96 basilisk96 at gmail.com
Wed Jan 9 21:59:52 EST 2008


On Jan 1, 12:11 am, Scott David Daniels <Scott.Dani... at Acm.Org> wrote:
> 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

Cool, thanks for posting this example and clearing that up.  Several
times in the past I have used super(self.__class__, cls) instead of
super(Klass_obj, cls), without a clue that it would wreck the
subclasses. My beginner's thought at the time was that it would
provide more flexibility.. Good thing I haven't had to subclass
them..yet :)

Cheers,
-Basilisk96



More information about the Python-list mailing list