Dynamic variable creation from string

alex23 wuwei23 at gmail.com
Mon Dec 12 02:11:18 EST 2011


On Dec 8, 3:09 am, Massi <massi_... at msn.com> wrote:
> in my script I have a dictionary whose items are couples in the form
> (string, integer values), say
>
> D = {'a':1, 'b':2, 'c':3}
>
> This dictionary is passed to a function as a parameter, e.g. :
>
> def Sum(D) :
>     return D['a']+D['b']+D['c']
>
> Is there a way to create three variables dynamically inside Sum in
> order to re write the function like this?
>
> def Sum(D) :
>     # Here some magic to create a,b,c from D
>     return a+b+c

Okay, here's a possible solution that doesn't rely on exec, but does
use the third-party module byteplay (which I believe limits it to
Python 2.5-2.7) and tries to retain as much as possible your syntax
(with some slight adjustments):

    from byteplay import Code, opmap

    class VariableInjector(dict):
        def transmute(self, opcode, arg):
            if (opcode == opmap['LOAD_GLOBAL']) and (arg in self):
                self._transmuted.append(arg)
                return opmap['LOAD_FAST'], arg
            return opcode, arg

        def make_locals(self, args):
            locals = []
            for arg in args:
                locals.append((opmap['LOAD_CONST'], self[arg]))
                locals.append((opmap['STORE_FAST'], arg))
            return locals

        def bind_to(self, function):
            function.ofunc_code = function.func_code
            def _(*args, **kwargs):
                self._transmuted = []
                code = Code.from_code(function.ofunc_code)
                code.code = [self.transmute(op, arg) for op, arg in
code.code]
                code.code = self.make_locals(self._transmuted) +
code.code
                function.func_code = code.to_code()
                return function(*args, **kwargs)
            return _

For your example, you'd use it like this:

    >>> def sum():
    ...     return a + b + c
    ...
    >>> def product():
    ...     return a * b * c
    ...
    >>> data = VariableInjector(a=1,b=2,c=3)
    >>> sum = data.bind_to(sum)
    >>> product = data.bind_to(product)
    >>> sum()
    6
    >>> product()
    6
    >>> data
    {'a': 1, 'c': 3, 'b': 2}
    >>> data['a'] = 100
    >>> sum()
    105
    >>> product()
    600

I'm not sure how rigorous this would be in real use but it's passed
the few quick toy cases I've tried it out on.

Any thanks should go to Michael Foord, as this borrows heavily from
his self-less metaclass example:
http://www.voidspace.org.uk/python/articles/metaclasses.shtml



More information about the Python-list mailing list