在Python

时间:2019-10-06 22:22:18

标签: python python-3.7

我有一个用户输入的数字数组。现在,我希望用户输入一个表达式(例如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评估用户输入的表达式。关于如何使其工作或以其他方式可以将功能用作输入的任何想法?

2 个答案:

答案 0 :(得分:0)

简单答案

您可以将函数导入全局范围,然后按如下所示从全局变量中获取它们:

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给定的属性会自动读取点符号,因此您可以使用它来做一些漂亮的技巧。如果没有属性(.__getitem__()),它也有一些尝试尝试obj[attr]

不利之处在于,如果您在getattr_loop中有一个非常深层的嵌套属性,RecursionError会给您一个obj

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

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

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

如果您希望直接使用sin,则需要将其直接导入名称空间。

有关安全性的注意事项

从安全的角度来看,抢劫globals()的事物可能会有风险。如果需要此保护,请确保:

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

享受!

答案 1 :(得分:0)

此代码应适用于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)