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

Carlos Ribeiro carribeiro at gmail.com
Wed Oct 6 07:25:06 EDT 2004


In respectful consideration to Alex's opposition to the misuse of the
word 'declaration', here is a repost with the suggested changes:
---
As part of a pet project of mine, I needed to find a way to re-execute
a class statement. The reason behind it was simple: the class
statement 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 statement block again to produce new
classes (in opposition to new instances, which would not solve my
problem)[1].

I solved the problem using inspect to find the current code object
*inside* the class statement, and stored it in 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] 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