将字符串转换为操作

时间:2018-06-08 02:53:44

标签: python python-3.x

有没有办法将带变量的字符串转换为操作?

例如

a = 3
b = 7

str = 'a * b'

# *MAGIC SOLUTION TO TURN IT INTO AN OPERATION*

print (str) # Prints 21

不要给别人解决问题,因为我知道通过不同的方式很容易做到。但我真的需要它来解决更难的问题

4 个答案:

答案 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的情况下建立一个等式。