Dynamic variable creation from string

A

alex23

For me, half of it is to avoid the typing, the other half to avoid the
reading.  ;)

Believe me, I get that, I've been more than guilty of it in the
past :)

But the reading here is important. If I see a dictionary lookup, I
expect it to be accessing a dictionary; if I see an attribute
reference, it might be wrapped in a descriptor. (And yes, I'm very
much aware that ultimately an attribute lookup _is_ a dictionary
lookup, but it's everything else that potentially happens after that
point that is important here.) Changing the visual short circuits any
understandings; then again, I tend to hate pesudo/mini-DSLs for the
same reason... I can't just rely on my understanding of the language,
I need to understand a specific implementation and mentally flag
whether it's relevant or not.

I also don't understand the original desire to create dynamic
variables either. Either you know the names in advance, in which case
just set up the necessary scaffolding to inject them where you need
them, or you _don't_ and there's no value in creating them anyway
because you don't know how to refer to them in your code.

So if you know the names, use dictionary unpacking:

userData = dict(a = 1, b = 2, c = 3)

def func(a,b,c):
return a + b + c
6

If the dictionary has more values than you need, catch & discard the
ones you don't want in **kwargs.
 
A

alex23

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:
... return a + b + c
...... 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
 
8

88888 Dihedral

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:
... return a + b + c
...... 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
 
8

88888 Dihedral

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:
... return a + b + c
...... 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

This is the way to write an assembler or
to roll out a script language to be included in an app
by users.
 
A

alex23

This is the way to write an assembler or
to roll out a script language to be included in an app
by users.

This is a garbage comment that has absolutely nothing to do with the
topic at hand _at all_.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
DewittMill
Top