Re-executing the code object from a class 'declaration'
carribeiro at gmail.com
Wed Oct 6 22:10:16 CEST 2004
On Wed, 6 Oct 2004 21:28:40 +0200, Alex Martelli <aleaxit at yahoo.com> wrote:
> Carlos Ribeiro <carribeiro at gmail.com> wrote:
> > > 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).
> I don't think you're missing anything -- just DO consider that if you
> pass your own globals they'll be used to solve every name that's not
> local to the class body, e.g. a '__metaclass__ = metaname' assignment in
> classbody (of course, you can finesse this by calling the metaclass
> explicitly anyway;-).
I was missing the new.function() call -- I hadn't checked how could I
build a function out of a code block up to that point, and I was
afraid that I would need to dive deeply into Python internals. It's
not that bad.
> > > 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.
> Nope, f doesn't get the bases AT ALL; the bases (as a tuple) go in only
> when you call the metaclass.
Well. I was mistaken (and that's not be the first time). It goes like
this; I first checked the dis.dis() code:
27 64 LOAD_CONST 4 ('MyClass')
67 LOAD_NAME 7 (object)
70 BUILD_TUPLE 1
73 LOAD_CONST 5 (<code object MyClass at
0120A0A0, file "c:\work\help-on-c-l-py\re_exec_class.py", line 27>)
76 MAKE_FUNCTION 0
79 CALL_FUNCTION 0
83 STORE_NAME 8 (MyClass)
... with that build_tuple there... besides that I knew I *can* access
the bases from within my class statement body:
bar = MyBaseClass.foo
... so I had suspected that the bases *were* passed to f(). But wait!
Actually, Python is building the stack for the BUILD_CLASS opcode.
> > > 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.
> OK, then, that's where you pass the bases in, not before.
> > For now, I think I'll just be using the class-inside-a-def idiom. But
> If it can give you all you need, that may be best.
> > 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.
> OK, keep us informed of developments, then!
Consultoria em Projetos
mail: carribeiro at gmail.com
mail: carribeiro at yahoo.com
More information about the Python-list