Re-executing the code object from a class 'declaration'

Carlos Ribeiro carribeiro at gmail.com
Tue Oct 5 22:09:26 EDT 2004


As part of a pet project of mine, I needed to find a way to re-execute
a class declaration[1]. The reason behind it was simple: the class
declaration in question had some external dependencies that could
potentially change during the lifetime of the program. I needed to be
able to execute the class 'declaration' block again to produce new
classes (in opposition to new instances, which would not solve my
problem)[2].

I solved the problem using inspect to find the current code object
*inside* the class declaration, and stored it an attribute of the
class itself. Then, a method of the class can be used to re-create it.
A metaclass-enabled version is shown below:

class Meta(type):
    def __new__(klass, name, bases, dct):
        dct['my_code'] = inspect.currentframe(1).f_code
        return type(name, bases, dct)

class MyClass:
    __metaclass__ = Meta
    creation_time = time.ctime()
    print "I'm inside my class definition!"
    def re_execute(klass):
        exec klass.my_code
        return MyClass
    re_execute = classmethod(re_execute)

Testing:

>>> class MyClass: 
        ...
I'm inside my class definition!
>>> id(MyClass)
8737376
>>> MyClass.creation_time
'Tue Oct 05 21:50:25 2004'
>>> NewClass = MyClass.re_execute()
I'm inside my class definition!
>>> id(NewClass)
8736912
>>> NewClass.creation_time
'Tue Oct 05 21:51:20 2004'

Implementation notes:

1) The exec statement actually binds the name to the same original
name, but in the current local scope. That's why it does a 'return
MyClass' in the re_execute() method. The MyClass symbol refers to the
local symbol with this name that was just re-created by the exec
method.

2) If you call the exec from the same scope where the class was
originally created, then it is automatically bound to the same name:

>>> id(MyClass)
8737376
>>> MyClass.creation_time
'Tue Oct 05 21:50:25 2004'
>>> exec MyClass.my_code
I'm inside my class definition!
>>> id(MyClass)
8744512
>>> MyClass.creation_time
'Tue Oct 05 21:56:53 2004'

3) I thought that the same technique could be made to work without a
metaclass, but I couldn't make it work. I haven't invested much time
to understand why -- it just works as implemented above. (It seems
that it does not bind correctly to the original name as it does if you
use the metaclass)

----
[1] After a long and interesting discussion for which I have to thank
Alex Martelli and several other members of c.l.py, I've come to
realize that there are no real class declarations in Python. But for
all effects, it's just easier to call them this way, even if the
underlying mechanism is different from the one used on other
traditional languages.

[2] Think about it as a templating mechanism, similar to the C++ one,
but for Python; this mechanism generates new classes that can be
instantiated as many times as needed. It's not the same thing as to
customize a instance during its initialization.

-- 
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: carribeiro at gmail.com
mail: carribeiro at yahoo.com



More information about the Python-list mailing list