Reputation: 113
I have a Python expression that looks like the following:
var1 = 'GOOGLE'
var2 = '5'
expr = 'df[df[var1]>=var2]'
In my workspace var1 and var2 are well defined so I can evaluate expr as follows:
eval(expr)
However, I want to pass this expr (as string) to another function with values of var1 and var2 substituted in it. I do not want to pass the variables var1 and var2, as I can have any number of variables, not just two. How do I accomplish this?
Upvotes: 2
Views: 500
Reputation: 1193
The "proper" way would be to do use ast.parse
, as @blhsing recommended. Still, in many cases this may be an overkill. In your simple case and similar cases, this is what I would do:
import re
expression = "3*x + function_x(y)"
values = {'x': 2, 'y': 5} # feel free to use a subset of `globals()` or `locals()` here, to reflect your workspace
# Substitute variable symbols with their values
for var, val in values.items():
pattern = r'\b' + re.escape(var) + r'\b'
expression = re.sub(pattern, str(val), expression)
assert(expression == "3*2 + function_x(5)")
The r'\b'
pattern ensures that you only match whole-word occurences, in case a variable exists as a substring of another variable or function/built-in name etc (like x
here exists in function_x
).
The re.escape()
function is necessary when you have variable symbols that contain special characters that have a special meaning in regular expressions. For example, the variable symbol itself could contain a special character, such as a .
: y.z
.
Upvotes: 0
Reputation: 107124
You can parse the expression with ast.parse
and use a subclass of ast.NodeTransformer
to convert Name
nodes to the corresponding values as Constant
nodes, and then convert the AST back to code with ast.unparse
:
import ast
var1 = 'GOOGLE'
var2 = '5'
expr = 'df[df[var1]>=var2]'
class NamesToConstants(ast.NodeTransformer):
def visit_Name(self, node):
if node.id in globals(): # feel free to use your own dict instead of globals()
value = globals()[node.id]
try: # convert value to integer if viable
value = int(value)
except:
pass
return ast.Constant(value=value)
return node
tree = ast.parse(expr)
NamesToConstants().visit(tree)
print(ast.unparse(tree))
This outputs:
df[df['GOOGLE'] >= 5]
ast.unparse
requires Python 3.10 or later. If you're using an earlier version, you can use astunparse.unparse
from the astunparse package instead.
Demo: https://trinket.io/python3/18cc1182d0
Upvotes: 2
Reputation: 1322
You can simply use Python f-string as demonstrated below
expr = f'df[df[{var1}] >= {var2}]'
Upvotes: 1