Limits of Metaprogramming
Wilson
PaulAlexWilson at gmail.com
Wed Aug 6 08:24:14 EDT 2008
On Aug 4, 9:23 pm, castironpi <castiro... at gmail.com> wrote:
> On Aug 4, 1:57 pm, Wilson <PaulAlexWil... at gmail.com> wrote:
>
> > On Aug 4, 6:49 pm, castironpi <castiro... at gmail.com> wrote:
>
> > > Two, if all your methods will have uniform signatures and closures,
> > > you can store class methods as only their co_code objects:
>
> > > >>> C.g.im_func.func_code.co_code
>
> > > 'd\x00\x00S'
>
> > > And fabricate them dynamically into full live types as needed.
>
> > Thanks for your comments and advice. This second option intrigues me;
> > could you elaborate further, I don't follow you...
>
> > Thanks Paul
>
> Depending on the complexity of the functions, a code string could be
> all you need to store to determine (redetermine) a function's
> behavior. For something moderately simple,
>
> def trans1( self, prev, trans ):
> if prev== 0 and trans== 'a':
> return 1
> if prev== 1 and trans== 'b':
> return 0
> return prev
>
> I found you need to store code.co_nlocals, code.co_code, and
> code.co_consts, to distinguish from a blank stub. With extra
> variables, I needed code.co_names and code.co_varnames too. To
> recreate a code object completely, you need 12 variables (14 to
> include closures), some of which are composite objects and would need
> to be pickled to be stored.
>
> Then you can build a new code object, then a new function object, then
> a new method object, then you can call it. Instead of a module of
> code, perhaps you could have a datafile containing only these values,
> up to twelve per record, one record for each different function you
> have.
>
> Here is the benefit:
>
> newcode= dupecode( oldcode, codet1 )
> newfun= FunctionType( newcode, {} )
> stub.stub= MethodType( newfun, stub )
> prev= stub.stub( prev, trans )
> print prev
>
> You can loop over these five lines, re-loading function data with
> 'dupecode', executing it, then reloading the next one, and you have a
> different function. Additions to your database of functions would
> start in source first (unless you construct each parameter, in
> particular co_code, by hand, which you may want), then get compiled,
> then go in.
>
> Here is the complete constructor for a code object:
>
> >>> help(_)
>
> Help on code object:
>
> class code(object)
> | code(argcount, nlocals, stacksize, flags, codestring, constants,
> names,
> | varnames, filename, name, firstlineno, lnotab[, freevars[,
> cellvars]])
>
> Here's the constructor in Python 3.0:
>
> class code(object)
> | code(argcount, kwonlyargcount nlocals, stacksize, flags,
> codestring,
> | constants, names, varnames, filename, name, firstlineno,
> | lnotab[, freevars[, cellvars]])
>
> I defined Stub.stub like this:
>
> class Stub:
> def stub( self, prev, trans ):
> return prev
> stub= Stub( )
>
> You need imports from the types module:
>
> from types import MethodType, FunctionType, CodeType
>
> And here is 'dupecode', which currently only replaces five of the old
> function's members with new ones:
>
> def dupecode( old, new ):
>
> newcode= CodeType( old.co_argcount, new.co_nlocals, old.co_stacksize,
> old.co_flags,
> new.co_code,
> new.co_consts, new.co_names,
> new.co_varnames, old.co_filename, old.co_name, old.co_firstlineno,
> old.co_lnotab )
>
> return newcode
Still don't really understand this so I'm going to admit defeat.
Thanks all for your advice... Very much appreciated!
More information about the Python-list
mailing list