"inherited" keyword in Python?

Alex Martelli aleaxit at yahoo.com
Tue Dec 5 16:11:08 EST 2000


"Paul Foley" <see at below> wrote in message
news:m266kzhua6.fsf at mycroft.actrix.gen.nz...
    [snip]
> > I think your cpl function is much more complicated than what's needed
> > to reproduce Python's very simple rule for walking the DAG of base
> > classes (it's just depth-first, left-first), even assuming it does
> > end up reproducing it perfectly.  But that's not the main point.
>
> It's probably much more complicated than it needs to be to do what it
> does, but it's not intended to reproduce Python's rule exactly -- that
> rule doesn't allow for a correctly-functioning "super" function in the
> presence of multiple inheritance.

Aha, I think I see what you mean.  But I also think you're wrong!

> My cpl() uses the CLOS rule, which is similar to Python but not
> broken.  The entire class hierarchy is sorted in such a way that
> classes appearing to the left of other classes in __bases__ appear
> before them in the sorted list, every class appears before any of its
> bases, and each appears exactly once.  Every method is reachable, not
> just the ones up the left branch, as in Python.

To clarify: Python's rule (as applied by, e.g., getattr) is anything
but broken, but it doesn't easily let you return (for a given class X
that inherits from A, B, C, ...) a single class Z that will ensure that
getattr(Z,whatever) is the same as getattr(X,whatever) for any
whatever that is not a key in X.__dict__.

Solution: generate an artificial class W with an empty __dict__
and exactly the same bases as X!

import new
def super(klass):
    return new.classobj('super_%s'%klass.__name__,
        klass.__bases__, {})

Of course, you can cache this as klass.__cached_super or whatever,
just as you did.


> > A more interesting theoretical question is how you propose to solve
> > the case in which you can't tell which class the current method
    [snip]
> If all else fails, take the easy way out and specify it in the call to
> super()

As I did above, yes.  But the 'convenience' rather takes a hit there.


> > class A:
> >     def foo(self):
> >         print super()
>
> At first reading, I didn't understand this: I thought it should be an
> error, since there are no superclasses.  Reading further, I understand
> that you expect super() to return one of the base classes.  Of course,
> that won't work.  I thought super() was just supposed to call the
> appropriate same-named method of a parent class.  Anything else can be
> done through the usual self.whatever, surely?

Not really.  To translate literally a Java class which has methods X
(which calls the base's Y) and Y (which calls the base's X method),
I'd need a Python's super() to be like Java's super (returning a class
object reference) and not like what I name 'supercall'.  self.X and
self.Y just won't do for this.


> > class B(A):
> >     def foo(self):
> >         print super()
> >         A.foo(self)
>
> > class C(A):
> >     def foo(self):
> >         print super()
> >         A.foo(self)
>
> > class D(B,C):
> >     def foo(self):
> >         print super()
> >         B.foo(self)
> >         C.foo(self)
>
> In this case, the CPL would be [D B C A], super() in D.foo() would
> call B.foo(), whose call to super() would call C.foo(), whose call to
> super() would call A.foo(), whose call to super() would signal an error.

I would have expected super() to return None for a bases-less class,
but it will now return (with my implementation above) an artificial
class with no bases and an empty dictionary.  So, my code above
would work, though not very usefully:-).


> > which reduces it to something decently-simple, like:
>
> > def supercall(_obj, _cls, _metnam, *args, **kwds):
> >     for _bas in _cls.__bases__:
> >         _metobj = getattr(_bas, _metnam, None)
> >         if not _metobj is None:
> >             return _metobj(_obj, *args, **kwds)
> >     else:
> >         raise NameError, "No superclass of %s has method %s" % (
> >             _cls, _metnam)
>
> > But, how often is it going to be satisfactory to call 'just
> > the one' (of several) inherited-method of a certain name, in
> > a multiple-inheritance context?  Just as often we may want
>
> It isn't (at least, not to me), which is why I avoided doing it that

But you did do that -- you call just one of the several 'inherited'
implementations of the method, in the code below.

> way.  Having figured out how to get the frame info, here's an
> implementation.  No need to pass in the object and method name:

I'd still want to pass them, at least optionally, to handle the
above case where I want to call a _different_ inherited method.
They can default to None to ask them to be obtained via
introspection, of course, if one wants that.

> If you just call super(__thisclass) with no args other than the class,
> it passes on the args the calling method got; or you can specify other
> args explicitly [yes, I know this prevents you calling with no args if
> super's caller has args]

As, once again, convenience gets in the way of simplicity and
generality.  Oh well:-).  "Tantum convenientia potuit suadere
malorum", as Lucretius might write if he lived today!-)


Alex






More information about the Python-list mailing list