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

Alex Martelli aleaxit at yahoo.com
Wed Oct 6 12:49:58 EDT 2004


Carlos Ribeiro <carribeiro at gmail.com> wrote:
   ...
> > module and place a dis.dis(dct['my_code']) in the metaclass's __new__
> > and you'll see that basically MyClass.re_execute isn't very different
> > from a reload of the module.  Isn't that a _bit_ too much in general?
> 
> (repeating to myself: dis is your friend. dis is your friend).

If you're hacking at this level, it sure is;-).

> done a few more tests. I found a way to find the correct code object
> for the _body_ of the class statement (or at least I think so), but

Good -- as I said I think it can be even more reliably found from inside
the classbody itself, but, no big deal.

>         exec klass.my_code

Ah, this is your problem -- that's not what you want to do now.

> problem is that the code block that is found refers to the class
> _body_ only. Checking dis.dis() helps to understand it:

Exactly: it's what builds the dict you want to pass to the metaclass
(once you wrap it into a new.function, as I mentioned).

> There is not a single code block that does all the tasks related to
> the class statement, and only it. In fact, there are two different
> code objects to choose from, and neither really solves the problem.

Not by itself, but add some code and you'll be fine.

1. You need to build an f = new.function(klass.my_code, globals()) in
   your classmethod that now erroneously does the exec above quoted (you
   could in fact do this in the metaclass, save the new function rather
   than the code object -- get the right globals via inspect).

2. you need to obtain the needed dict, that's just  d = f()  in your
   method

3. you can now call your metaclass with the appropriate bases and name:
       klas = self.__class__  # or cls if this is a classmethod;-)
       return type(klas)(klas.__name__, klas.__bases__, d)

voila, you're there.  This is all coded to minimize the need to have
this method located in a specific class -- as I said I think you
probably want to have this stuff in the metaclass (if you have a
metaclass at all), but, whatever.


This is basically just mimicking what Python itself does (check the
dis.dis for a class statement as a starter): get the class body's code
object, build a function from it, call the function (it returns its
locals() as the result -- that 'return' is of course in the class body's
code object, and dis.dis shows that...), and that's how you get the
classdict on the stack.  Add name and bases, call the metaclass, and
Bob's your uncle...


Alex



More information about the Python-list mailing list