Defining a Custom Metaclass to Control Class Behavior
Credit: Luther Blissett
Problem
You want to control the behavior of a class object and all of its instance objects, paying minimal runtime costs.
Solution
Python 2.2 lets you easily define your own custom metaclasses so you can build class objects whose behavior is entirely under your control, without runtime overhead except when the classes are created. For example, if you want to ensure that all methods a class defines (but not those it inherits and doesn’t override) are traced, a custom metaclass that wraps the methods at class-creation time is easy to write:
# requires Python 2.2 or later
import types
def tracing(f, name):
def traced_f(*a, **k):
print '%s(%s,%s) ->'%(name,a,k),
result = f(*a, **k)
print result
return result
return traced_f
class meta_tracer(type):
def _ _new_ _(self, classname, bases, classdict):
for f in classdict:
m = classdict[f]
if isinstance(m, types.FunctionType):
classdict[f] = tracing(m, '%s.%s'%(classname,f))
return type._ _new_ _(self, classname, bases, classdict)
class tracer:
_ _metaclass_ _ = meta_tracerDiscussion
This recipe’s
tracing
function is nothing special—it’s just a
tracing wrapper closure that makes good use of the lexically nested
scopes supported in Python 2.2 (or 2.1 with from _ _future_ _ import nested_scopes). We could use such a wrapper
explicitly in each class that needs to be traced. For example:
class prova: def a(self): print 'body: prova.a' a = tracing(a, 'prova.a') def b(self): ...