即时定义 sympy.abc 个变量:名称错误处理

Defining sympy.abc variables on the fly : name error handling

我正在尝试使用可以包含任何 abc 字母的 eval SymPy 表达式进行计算:

from sympy.abc import *

我想在一个方法中实现一种通过动态定义相关变量来处理 NameError 的方法。这是它的要点

try:
    eval(expr)
except NameError as err:
    msg = str(err)
    pos = msg.find("'")
    letter = msg[pos+1]
    from sympy.abc import letter

显然sympy.abc中没有一个叫字母的字母。所以这会引发异常。另一个问题是,如果使用像 theta 这样的符号,则只会评估该符号的第一个字母。所以关于我如何首先设法导入字母值的任何提示,也许还可以处理像 eta、phi 等符号。

另一个重要的问题是表达式中可以有很多不同的字母。我该如何处理?

Edit : 我几乎已经解决了这个问题。 这是我的尝试:

def try_expr(expr):
    try:
        eval(expr)
    except NameError as err:
        msg = str(err)
        pos = msg.find("'")
        letter = msg[pos+1]
        pos = pos +1
        found = False
        while (pos+1 < len(msg)) and (not found):
            more = msg[pos+1]
            for symb in symbols:
                if more==symb or more.isdigit():
                    found = True
                    break
                if found is False:
                    letter = letter+more       
                    pos = pos + 1
        for alphabet in abc.__dict__:
            if letter == alphabet:
                exec('from sympy.abc import %s'%alphabet)
                letters.append(alphabet)
                try_expr(expr) # try to evaluate the expression again
import sympy.abc as abc
symbols = ['*','/','(',')',"'"]
letters = [] # for storing any letters that are in the expression
try_expr('2*theta')

我已经成功地从 sympy.abc 中导入了第一个未知变量(无论它是单个字符还是像 'theta' 这样的希腊字母。然而,当我尝试递归调用该函数时为了找到任何其他未知数,我设法导入的字母再次被提升为未知数。在此过程中,我最终得到 RuntimeError : maximum recursion depth exceeded while getting the str of an object.

这是代码,有一个 运行 例子

import sympy.abc as abc
symbols = ['*','/','(',')',"'",'"']
letters = []
def try_expr(expr):
    try:
        for letter in letters:
            exec('from sympy.abc import %s'%letter) # re-execute after finding each unknown variable
        l = expr.count('(')
        r = expr.count(')')
        if l == r:         
            eval(expr)
        elif l < r:
            eval((r-l)*'('+expr)
    except NameError as err:
        msg = str(err)
        pos = msg.find("'")
        letter = msg[pos+1]
        pos = pos +1
        found = False
        while (pos+1 < len(msg)) and (not found): # check for multi-char greek letters
            more = msg[pos+1]
            for symb in symbols:
                if more==symb or more.isdigit():
                    found = True
                    break
            if found is False:
                letter = letter+more       
                pos = pos + 1
        for alphabet in abc.__dict__:
            if letter == alphabet:
                letters.append(alphabet)
                try_expr(expr[expr.find(alphabet):]) # search for the next unknown variable

from sympy import sin, sqrt, log, exp, cos, tanh, sinh, cosh, atan, acos, asin
import sys
if len(sys.argv) == 1:
    expr = '(sin(x**2)-log(exp(2*y))) + cos(x**2) + a + b + c + theta*eta'
else:
    expr = sys.argv[1]
try_expr(expr)
for letter in letters:
    exec('from sympy.abc import %s'%letter)
print 'The SymPy expression %s contains the following letters : %s' %(eval('%s'%expr), letters)

编辑:添加了对拆分后计算表达式时不平衡括号的修复。