how do I change the values of variables dynamically in a string?

Viewed 117

I extracted a mathematical string from text e-g s = "a&(b|c)" and I want to use eval(s) but before I do, I have to assign values to the variables something like:

a, b, c  = somefuction()

how do I do this dynamically like

r = re.findall("\w+", s)    
r[0], r[1], r[2] = somefunction()

and then pass back these value to the variables and use eval() on it. My end output should give me True of False based on the values of a,b,c

2 Answers

Assuming findall does find your variables correctly, and your function returns the appropriate tuple, then you could use exec to set the variables:

r = re.findall("\w+", s)
vars = ', '.join(r)
exec(vars + ' = somefunction()')

In your example this will construct the string a, b, c = somefunction() and execute it, resulting in the variables being set in the current namespace.

Since in the comment you state that the number of variables may vary, you might want to send that number to your function:

exec('{} = somefunction({})'.format(vars, len(r)))

Alternatively, if your function always returns the same number of elements but one or more might not be used depending on the extracted mathematical expression, you may want to append or prepend _ (underscore) to the vars string to take the place of unused values.

Use a dict instead of variable variables, following from How do I create a variable number of variables?

This is the best way I've found to do it, but I'm sure it could be shorter:

import re

s = "a&(b|c)"
sometuple = 7, 1, 2  # Stand-in for "somefunction()"

names = re.findall(r"\w+", s)
vals = {name: val for name, val in zip(names, sometuple)}  # Map names to values
# > {'a': 7, 'b': 1, 'c': 2}

s_spec = re.sub(r"(\w+)", r'{\1}', s)  # Mark names for interpolation
# > '{a}&({b}|{c})'

filled = s_spec.format(**vals)  # Interpolate
# > '7&(1|2)'

print(eval(filled))  # -> 3
Related