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

问题描述 投票:0回答:2

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

python python-3.7
2个回答
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)

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中递归搜索属性attr的函数。 attr给定的属性会自动读取点符号,因此您可以使用它来做一些漂亮的技巧。如果没有属性(.__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之类的内容并造成一些伤害...
  • 享受!

© www.soinside.com 2019 - 2024. All rights reserved.