Hooks (Re: What does Python fix?)
Alex Martelli
aleax at aleax.it
Tue Jan 22 03:51:52 EST 2002
"hungjunglu" <hungjunglu at yahoo.com> wrote in message
news:mailman.1011682659.11920.python-list at python.org...
...
> class A:
> def f(self, x):
...
> A.f_old = A.f
> A.f = new.instancemethod(g, None, A)
...
> (I use Python 2.1. I have not checked the situation in 2.2.) Anyway,
When you subclass A from object or another builtin type, in
2.2 new.instancemethod doesn't work (as discussed in another
thread). However, you don't even NEED it in the first place:
>>> class A(object):
... def f(self): print "old f"
...
>>> a=A()
>>> a.f()
old f
>>> def g(self):
... print "before f"
... self.old_f()
... print "after f"
...
>>> A.old_f=A.f
>>> A.f=g
>>> a.f()
before f
old f
after f
>>>
Whether A is a classic-class or a new-style 2.2 class (derived
from object or another builtin), this "just works".
It's interesting, at least in theory, to evolve this into a
full-fledged "Aspect" modifier that systematically wraps
every method-call into a before-and-after wrapper (presumably
what you call "hooks"). Doing it via a metaclass seems the
natural approach, but I don't quite see how to make it work
"retroactively and non-invasively" on already-instantiated
instances of the class being "Aspected". Doing it via
__getattr__ hits the difficult snag of removing the methods
from the class's namespace (otherwise __getattr__ does not
get called). So, it seems easier to do in 2.2, given the
new __getattribute__ (which IS called whether a given
attribute is in the class's namespace, or not).
Here's a very-elementary, doesn't-even-consider-most-
important-concerns proof-of-concept for this idea:
>>> def Aspecter(class_, wrapperfun):
... base_getattribute = class_.__getattribute__
... def __getattribute__(self, name):
... attribute = base_getattribute(self, name)
... if callable(attribute):
... attribute = wrapperfun(name, class_, attribute)
... return attribute
... class_.__getattribute__ = __getattribute__
...
>>> def wrapperfun(name, class_, method):
... def wrapper(*args):
... print "before method",name
... result = method(*args)
... print "after method",name
... return result
... return wrapper
...
>>> Aspecter(A, wrapperfun)
>>> a.f()
before method f
before f
before method old_f
old f
after method old_f
after f
after method f
>>>
Note that Aspecter and wrapperfun also make rather
unabashed use of nested scopes:-).
Unfortunately, this does NOT work with old-style
classes, since they lack __getattribute__. One of
the several concerns that should somehow be met to
make this into a somewhat-useful component:-).
Alex
More information about the Python-list
mailing list