获取表达式作为 python 中的输入

Get an expression as an input in python

我有一个用户输入的数字数组。现在,我希望用户输入一个表达式(例如,sin (x))并且我想使用数组中的数字计算该表达式。 我不知道如何从用户那里获取表达式作为输入,然后根据数组对其进行评估。

到目前为止我有:

collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
    n = input("Enter number:")
    collection.append(int(n))
print ('ARRAY: ',collection)

def function_creator(): 

    expr = input("Enter the function(in terms of x):") 
    x = int(input("Enter the value of x:")) 
    safe_dict['x'] = x 
    y = eval(expr, {"__builtins__":None}, safe_dict) 
    print("y = {}".format(y)) 

if __name__ == "__main__": 
    safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 
                 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 
                 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 
                 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 
                 'tan', 'tanh'] 
    safe_dict = dict([(k, locals().get(k, None)) for k in safe_list]) 

    function_creator() 

我曾尝试使用 python 中的 eval() 函数获取表达式,但无法使其正常工作。为了分步工作,我现在不使用数组作为用户输入的表达式中的 x 变量。相反,我只是想用他们选择的 x 来评估用户输入的表达式。关于如何使它工作或我可以将函数作为输入的任何其他方式的任何想法?

简单回答

你可以将函数导入到全局作用域中,然后从全局中抓取它们,如下所示:

from numpy import sin

collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
    n = input("Enter number:")
    collection.append(int(n))
print ('ARRAY: ',collection)

func_name = input("Enter function: ")

try:
    ans = globals()[func_name](collection)
except KeyError:
    raise AttributeError('Function not found in namespace!')

print(ans)

稍微复杂一点的回答

您可以尝试以下代码片段:

import numpy as np

collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
    n = input("Enter number:")
    collection.append(int(n))
print ('ARRAY: ',collection)

func_name = input("Enter function: ")

def getattr_loop(obj,attr):
    '''getattr, or getitem, or error, in a loop, forever!'''
    spl = attr.split('.')
    if len(spl) > 1:
        try:
            return getattr_loop(getattr(obj,spl[0]),'.'.join(spl[1:]))
        except AttributeError as err:
            try:
                return getattr_loop(obj[spl[0]],'.'.join(spl[1:]))
            except KeyError:
                raise err
    else:
        return getattr(obj,spl[0])

# Compute using user defined function
try:
    ans = getattr_loop(globals(),func_name)(collection)
except AttributeError:
    raise AttributeError('Function not found in namespace!')

print(ans)

getattr_loop 是一个函数,它将递归搜索 obj 属性 attrattr 给出的属性自动读取点符号,因此您可以使用它来做一些漂亮的技巧。如果没有属性 (obj[attr])

,它还有一些尝试 .__getitem__() 的处理

缺点是 getattr_loop 会给你一个 RecursionError 如果你在 obj.

中有一个真正深层嵌套的属性

例如,如果使用 Numpy 模块作为对象:

>>> getattr_loop(np,'random.rand')

这将允许您访问 np.random.rand。如果您像代码片段中那样使用 globals(),它将获取在全局范围内定义的所有对象。因此,上述代码片段的用户可以键入 'np.sin' 作为函数,代码将计算 np.sin(collection).

如果您想直接使用 sin,您需要将其直接导入命名空间。

安全注意事项

globals() 抓取东西从安全角度来看可能存在风险。如果您需要确保安全,请确保:

  • 清理您的输入
  • 构造一个只包含您希望某人能够访问的功能的对象,以免您不小心允许某人修补成 os.remove 之类的东西并造成一些伤害...

尽情享受吧!

此代码适用于 x 中的表达式,例如 x*sin(x) + (x+1)*exp(2*x)

from math import *   # import sin, cos, tan, etc. into globals
                     # to allow use by eval

def function_creator(arr): 
  " allows expressions such as x*sin(x) + x "
  expr = input("Enter the function(in terms of x):")
  # x is bound locally inside the list comprehension for use by eval
  return [eval(expr) for x in arr]  # compute expression on each data element

if __name__ == "__main__": 
  collection = list()
  number = input("Enter the number of elements you want: ")
  for i in range(int(number)):
    n = input("Enter number:")
    collection.append(float(n))
  print ('ARRAY: ',collection)
  result = function_creator(collection)
  print(result)