Metaclass Question

Jay Parlar jparlar at cogeco.ca
Wed Oct 6 18:46:47 EDT 2004


(Apologies in advance for the size of this message)

I decided to finally bite the bullet, and become part of the 1% of 
people who understand metaclasses.

One of the examples of them I saw had to do with someone intercepting 
the __init__ method of classes, and doing some fun stuff. I decided to 
try something like that.

class MethodNameGetter(type):
     '''
     Any classes that use this metaclass can, at any time, reference
     self.current_function, to get the name of the current function
     being run
     '''

     '''
     key: name of a class
     value: { key: method reference, value: method name}
     '''
     nameReg = {}
     def __init__(cls, name, bases, dict_):
         super(MethodNameGetter, cls).__init__(name, bases, dict_)

         cls_dict = cls.__dict__
         funcs = [key for key, val in cls_dict.items() if type(val) == 
FunctionType]
         print funcs
         cls.nameReg[name] = {}
         for func_name in funcs:
             old_func = cls_dict[func_name]
             code = old_func.func_code
             defaults = old_func.func_defaults or ()
             p_args = code.co_varnames[1:code.co_argcount]
             p_kw = dict(zip(p_args[-len(defaults):], defaults))

             def new_func(self, *args, **kw):
                 while True:
                     nameReg = self.__class__.nameReg
                     func_name = 
nameReg[self.__class__.__name__][new_func]
                     setattr(self, "current_function", func_name)
                     t = eval("self._old_"+func_name)
                     print "t is", t
                     t(*args, **kw)
                     yield 0

             cls.nameReg[name][new_func] = func_name
             setattr(cls, "_old_" + func_name, old_func)
             setattr(cls, func_name, lambda 
*args,**kw:new_func(*args,**kw))


Essentially, what I'm trying to do here, is intercept all the methods 
defined in some class, and make it so that if you call any methods in a 
class, it will set self.current_function to the name of the method that 
was just called. This would let me easily grab the name of the current 
function being run, while being run.

My goal here isn't really the whole current_function thing, it's just 
to learn metaclasses.

My class here is close, but the problem is with my 'def new_func'. For 
some reason I assumed that "new instances" of it would get created for 
each method being overridden, but they're not.

If I do this:

class A:
     __metaclass__ = MethodNameGetter
     def foo(self):
         print "f"
         print self.current_function
     def bar(self):
         print "b"
         print self.current_function

t = A()
t.foo()
t.bar()

I should see:
 > f
 > foo
 > b
 > bar

Instead, I just see the stuff for foo(), two times.

Is there any way to make new instances of a function, short of a lambda?

Thanks in advance,
Jay P.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2363 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20041006/6bdd1c6b/attachment.bin>


More information about the Python-list mailing list