Metaclasses vs. standard Python reflection?
Dave Benjamin
ramen at lackingtalent.com
Tue May 6 12:04:14 EDT 2003
In article <zFKta.48587$3M4.1298130 at news1.tin.it>, Alex Martelli wrote:
> It has little to do with subclassing. A class is an INSTANCE of its
> metaclass -- the relation to subclasses is there, but tangential.
This I understand. I was just making the observation that defining
__metaclass__ within a class definition is a similar mechanism to defining
superclasses. It takes place in the class itself, in contrast to the idea of
externally applying "aspects" to a class. It's like saying "My metaclass
is..." instead of "My superclass is...". Is this accurate?
> You could track down the INSTANCES of Foo, or some of them, and
> reassign THEIR __class__. But Foo's own __class__ is generally NOT
> reassignable. If Foo.Foo wasn't yet instantiated of course you could
> easily rebind Foo.Foo = BarFoo, so FUTURE instantiations use the new
> class with Bar.Bar as its metaclass.
Okay, here's my attempt at illustrating this technique. I'll just take a
very simple class and rebind it within its module so that it appears to be
the same class but additionally logs the entry and exit of its methods:
Simple.py
---------
class Simple:
def __init__(self, x):
self.x = x
def print_x(self):
print 'x = %s' % self.x
Meta.py
-------
import Simple
def log_call(method):
def new_method(self, *args, **kwds):
print 'Entering %s...' % method
result = method(self, *args, **kwds)
print 'Exiting %s...' % method
return new_method
class Logger(type):
def __new__(cls, name, bases, dict):
for key in dict:
if callable(dict[key]):
dict[key] = log_call(dict[key])
return type.__new__(cls, name, bases, dict)
Simple.Simple = Logger(Simple.Simple.__name__,
Simple.Simple.__bases__,
Simple.Simple.__dict__)
s = Simple.Simple(123)
s.print_x()
Output
------
$ python Meta.py
Entering <function __init__ at 0x816ab54>...
Exiting <function __init__ at 0x816ab54>...
Entering <function print_x at 0x816cfec>...
x = 123
Exiting <function print_x at 0x816cfec>...
Discussion
----------
On the surface, this technique seems to achieve the desired result. However,
I have a hunch this will not work properly with inheritance. For instance,
if another class extends the Simple class before I rebind it, I will have to
apply Logger to those classes as well.
How could I achieve this effect with the global __metaclass__? I've tried
doing things like:
__metaclass__ = Logger
Simple.__metaclass__ = Logger
to no effect. I think I'm still very confused about how the metaclass
mechanism works.
Thanks for the reply,
Dave
More information about the Python-list
mailing list