Comparison with Ruby ?

Alex Martelli aleaxit at yahoo.com
Fri Feb 23 05:33:04 EST 2001


"Raymond Hettinger" <othello at javanet.com> wrote in message
news:3A95D2FB.5D7937A9 at javanet.com...
    [snip]
> I would like to see a version of 'super' that searches inherited classes
> in the same order that methods are searched for.  Super.method, should act
> like it would if the method were not found in the current class
definition.
> 'nuff said.

Generalizing this a bit (to find all attributes, rather
than just methods), you could just use the following
free-standing function:

def findSuperclassForAttributeName(self, attributeName):
    for base in self.__class__.__bases__:
        if hasattr(base, attributeName): return base
    else: return None

or, you could use a convenient mixin class, by having
your classes inherit from it:

class SuperFinder:
    [snip: method same as above]

but that's just for the syntax-sugar satisfaction of
being able to use this in a 'cooler' way, such as:

class Whatever(Abase,Anotherbase,SuperFinder):
    def floop(self, plik, plok):
        preFlooper(plok)
        super = self.findSuperclassForAttributeName('floop')
        if super is None: raise AttributeError
        super.floop(self, plok, plik)
        postFlooper(plik+23.7)

and if you're into 'cool' solutions (rather than simple
ones), then you can do even "better" -- e.g., here's a
less-general, but potentially interesting, approach:

import new
def bindInSuper(boundMethod):
    obj = boundMethod.im_self
    name = boundMethod.__name__
    for base in obj.__class__.__bases__:
        if hasattr(base, name): break
    else: raise AttributeError
    return new.instancemethod(getattr(base, name), obj, base)

leading to the usage pattern:

class Whatever(Abase,Anotherbase,SuperFinder):
    def floop(self, plik, plok):
        preFlooper(plok)
        bindInSuper(self.floop)(plok, plik)
        postFlooper(plik+23.7)


Note that this only works ONCE, to find ONE 'super', or
build one bound-method; e.g., the returned bound-method
of bindInSuper is a fixedpoint for it.  It would not
be TOO hard to work around this, by having bindInSuper
return an instance of a suitable special-purpose class,
that is both callable AND specialcased for further
searches on the inheritance DAG (you'd have to decide
exactly what sequence of [bound-methods wrapped into
suitable callable instances] you want to get from a
sequence of calls to bindInSuper in various cases, of
course:-).

But I'm going to leave this as an exercise to the
interested reader.  The real value of this fancy stuff
is not in truly making use of it in production code,
anyway -- it's in showing off on comp.lang.python,
ahem, I *mean*, in better understanding what IS going
on "behind the scenes" (but not "secretly" at all --
Python is wonderfully open about what its mechanisms
ARE doing on your behalf!!!).  In *practice*, one
should use *the simplest thing that can possibly work* --
and, unless one is building the next great development
and debugging environment, it is seldom indeed that
the "simplest thing" will require introspection and
metaprogramming facilities.


Alex






More information about the Python-list mailing list