有没有办法将带变量的字符串转换为操作?
例如
a = 3
b = 7
str = 'a * b'
# *MAGIC SOLUTION TO TURN IT INTO AN OPERATION*
print (str) # Prints 21
请不要给别人解决问题,因为我知道通过不同的方式很容易做到。但我真的需要它来解决更难的问题
答案 0 :(得分:4)
您可以使用内置operator
包并使用globals
from operator import sub, add, truediv, mul
import re
def string_eval(str_):
operators = {'-': sub, '+': add, '/': truediv, '*': mul}
pattern = re.compile(r'(.*?)\s*([*\/+-])\s*(.*)')
splited = re.search(pattern, str_).groups()
if len(splited) == 3:
a, ope, b = splited
val_a = globals()[a]
val_b = globals()[b]
return operators[ope](val_a, val_b)
现在要实现这一点,你必须首先声明变量
>>> a = 45
>>> b = 25
>>> string_eval('a - b')
20
>>> string_eval('a * b')
1125
答案 1 :(得分:3)
在Python 3.6+中,您可以使用literal string interpolation。
a = 3
b = 7
print(f'{a * b}') # prints: '21'
答案 2 :(得分:3)
我假设"不给别人解决问题的方法,因为我知道通过不同的方式很容易做到"将eval
称为您不想要的简单答案。
但实际上,你想要的几乎肯定是一个用某种语言解析和解释表达式的函数,就像eval
那样,它只是你想要一种比Python更简单,更受限制的语言,也许只是基本的算术表达式。
作为Olivier Melançon's answer shows,Python还在f-string评估器中为Python的有限子集提供了一个解释器,而jedwards' answer shows则提供了有效的类似语言的解释器。这样一个子集。
但是如果你想要完全按照你想要的方式处理你想要的语言,你必须自己做。它实际上并不像听起来那么可怕。我将使用Python自己的ast
模块进行解析,然后编写自己的解释器。只要你真的想要一个严格的Python子集,但是如果你想要一些不同的东西 - 例如,^
用于求幂(具有错误的优先级和关联性),或者那些不是有效Python的变量,这都可以工作标识符等,你也必须构建解析器。
import ast
import operator
ops = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
}
def interpret(expr, env):
if isinstance(expr, ast.Expr):
return interpret(expr.value, env)
elif isinstance(expr, ast.BinOp):
op = ops[type(expr.op)]
return op(interpret(expr.left, env), interpret(expr.right, env))
elif isinstance(expr, ast.Num):
return expr.n
elif isinstance(expr, ast.Name):
val = env[expr.id]
if isinstance(val, (bool, int, float, complex)):
return val
raise ValueError(val)
else:
raise ValueError(expr)
def evaluate(s, env=None):
if env is None: env = globals()
tree = ast.parse(s)
return interpret(tree.body[0], env)
现在,您可以使用基本的4算术运算符,括号,数字常量或值为数字的全局变量的名称来评估任何内容,但不能用其他内容:
>>> a = 3
>>> b = 7
>>> evaluate('a * b')
21
>>> evaluate('3*a + 2*(b+10)')
32
>>> evaluate('__import__("os")')
ValueError: <_ast.Call object at 0x109210da0>
>>> evaluate('a * b', {'a': 10, 'b': 1j})
10j
>>> evaluate('-2')
ValueError: <_ast.UnaryOp object at 0x1092fc5c0>
显然错误处理可能更好,我可能应该至少处理一元-
,以防你想要负数...但这应该足以得到重点。阅读上面链接的ast
文档,应该清楚如何进一步扩展它。
另一方面,Bijoy's answer是一个更简单的解析器和解释器。它不会处理更复杂的表达 - 但如果你不想要它,那就是一个功能,而不是一个bug。
答案 3 :(得分:1)
使用sympy库(docs)是一种方法:
from sympy import Symbol, sympify
# Define symbols
a = Symbol('a')
b = Symbol('b')
# Parse the string into an equation
eqn = sympify('a * b')
# Substitute values for variables
eqn = eqn.subs(a, 3)
eqn = eqn.subs(b, 7)
print(eqn) # Prints 21
或者,更接近您所写的内容(但我更喜欢它):
from sympy import sympify
a = 3
b = 7
# Parse the string into an equation
eqn = sympify('a * b', locals = locals())
print(eqn) # Prints 21
编辑提示:强烈提及失望,sympify
, the string-to-equation parsing command, using eval()
。 :悲伤的脸:
话虽如此,sympy是一个值得考虑的有用的库,你当然可以在不使用sympify
的情况下建立一个等式。