2

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

JaySabir
  • 322
  • 1
  • 10
  • 1
    If you use `eval()`, it will usually just use whatever variables are in the local namespace. If you've assigned variables named `a`, `b`, and `c` before calling `eval()`, then it should use their current values. – Green Cloak Guy Aug 29 '20 at 21:52
  • @GreenCloakGuy the problem is, I am extracting that string from a text. I have to assign the values later using somefunction. – JaySabir Aug 29 '20 at 21:57
  • 3
    You'd probably want to use `re.sub()` to replace them with, say, `{}`, and then use `str.format()` to substitute in the values you want. Without knowing what your input would look like, and what your output should look like, it's not possible to give much more of a comprehensive answer. – Green Cloak Guy Aug 29 '20 at 21:59
  • @GreenCloakGuy nice idea, let me try that. I was hoping there was a simpler pythonic way. – JaySabir Aug 29 '20 at 22:01
  • What do you know about the variables? Do you know how many there are, or does that change dynamically? Can you guarantee they are the only letter characters in the extracted string (i.e. "\w+" will actually extract correctly? – Lev M. Aug 29 '20 at 22:35
  • @LevM. only 4 to 5 variables in a function at a time. don't worry about the regex; only usable vaiable names will be extracted. – JaySabir Aug 29 '20 at 22:45

2 Answers2

1

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.

Lev M.
  • 6,088
  • 1
  • 10
  • 23
1

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
wjandrea
  • 28,235
  • 9
  • 60
  • 81