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

Carlos Ribeiro carribeiro at gmail.com
Wed Oct 6 13:14:16 EDT 2004


On Wed, 6 Oct 2004 18:49:58 +0200, Alex Martelli <aleaxit at yahoo.com> wrote:
> 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).

That's the part that I was missing. It looks less 'hackish' than I had
expect. I was really afraid that I would need to manage bytecode-level
hacks myself. I am not as concerned about getting the right globals,
though -- it's good enough if I'm able to supply whatever globals I
need upon calling, I think (unless I'm _really_ missing something).
 
> 2. you need to obtain the needed dict, that's just  d = f()  in your
>    method

There is still a question, but I think I already know the anwswer :-)
If the class *has* a base class, it has to be passed as a parameter. I
assume that i can simply call it like this: d=f(bases); or instead,
that I can fill the argdefs in the new.function call. I'll try it
later.

> 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.

Tehre are two reasons to do it in a metaclass: first, I tested it and
it works (of sorts), while for some reason it wont work for a
non-metaclasses enabled class. Also, because in this scenario there
are other things that I already need to check, and a metaclass does it
nicely.

> 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...

For now, I think I'll just be using the class-inside-a-def idiom. But
I'm still working around some design issues, and if the templating
mechanism gets in the final production code (it's only one of a few
competing designs), I'll surely try it again.

-- 
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