Python3: eval() with custom dict not evaluating numbers
Python3: eval() with custom dict not evaluating numbers
我正在开发一个应用程序,它允许用户通过输入字符串(就像您在 wolfram alpha 上看到的那样)来定义数学函数,并在某个预定义的范围内绘制该函数。我使用 eval() 函数来解释字符串并填充 y 值列表(已定义的 x 值列表)。我只允许 eval() 访问一些常见的 numpy 数学函数和变量名 'x'。
这 class 允许我为用户输入的每个字符串创建一个对象,并创建两个列表 x 和 y,以便使用 matplotlib 绘图。您可以 运行 这个 MWE 并看到它可以很好地处理 x 的函数(例如 sin(x)、ln(x)、3*x 等)并抛出非数学函数的异常,例如 'foo' 根据需要。但是,给它一个像“3”或“4.00”这样的数字会导致 eval() 不向 self.y 列表中写入任何内容。您可以在代码中的不同点打印 self.y 的形状,并且一旦 eval() 运行s(当输入的字符串是数字时)就会看到 self.y 的形状变成 ().
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
class functionType():
def __init__(self, funcStr, xlo=0.0, xhi=10.0, res=100):
self.x = []
self.y = []
self.xlo = xlo
self.xhi = xhi
self.res = res
self.funcStr = funcStr
self.x = np.linspace(self.xlo, self.xhi, self.res)
self.safe_dict = {'np':np,
'sin':np.sin,
'cos':np.cos,
'tan':np.tan,
'arcsin':np.arcsin,
'arccos':np.arccos,
'arctan':np.arctan,
'sinh':np.sinh,
'cosh':np.cosh,
'tanh':np.tanh,
'arcsinh':np.arcsinh,
'arccosh':np.arccosh,
'arctanh':np.arctanh,
'ln':np.log,
'log10':np.log10,
'log2':np.log2,
'exp':np.exp,
'sqrt':np.sqrt,
'abs':np.fabs,
'x':self.x}
try:
self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict)
except Exception:
raise Exception
def _reMakeData(self):
self.x = np.linspace(self.xlo, self.xhi, self.res)
self.safe_dict['x'] = self.x
self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict)
def setXLow(self, value):
self.xlo = value
self._reMakeData()
def setXHigh(self, value):
self.xhi = value
self._reMakeData()
def setRes(self, value):
self.res = value
self._reMakeData()
def getXLow(self):
return self.xlo
def getXHigh(self):
return self.xhi
def getRes(self):
return self.res
def getData(self):
return self.x, self.y
func = input("gimme a function: ")
try:
plot1 = functionType(func)
x, y = plot1.getData()
plt.plot(x,y,marker='',color='red')
plt.show()
except Exception as e:
print("no good: ",e)
有人看到这里的问题吗?我希望能够处理想要绘制常量函数的用户。需要明确的是,当我给它一个像 4.0 这样的常量时,我希望它将一个列表写入 self.y (它实际上是一个 1D numpy 数组,但我们不必迂腐)与 self.x 填充的长度相同4.0 的。
这不适用于 Web 或服务器应用程序,我完全了解 eval() 固有的风险,所以请不要犹豫使用它:)
问题是绘图需要 y 值列表与 x 值列表的长度相同。如果你输入的表达式涉及x
,这就可以正常工作,因为x
是一个numpy数组,所以对其进行数学运算将产生一个相同长度的数组。但是如果你只是输入一个数字 y
会被设置为一个数字,而不是一个数组。
一种可能是在设置y
后检查它是否是一个numpy数组,如果不是,则假设它是一个数字并重复适当的次数:
if not isinstance(self.y, np.ndarray):
self.y = np.repeat(self.y, len(self.x))
您的代码还有其他一些错误和奇怪的事情。在你传递给 eval
的字典中,你想使用 {'__builtins__': None}
,并在 __builtins__
周围加上引号。另外,您对 try/except 的使用毫无意义。执行 except Exception
后立即执行 raise Exception
没有任何作用,并且隐藏了有关引发何种异常的信息。只需删除 try/except;如果引发异常,它将向上传播,您将看到它是哪种异常。同样,您最后的 try/except 也没有用;它所做的只是打印一条消息,该消息的信息量少于如果您没有捕获异常时将打印的消息。
我正在开发一个应用程序,它允许用户通过输入字符串(就像您在 wolfram alpha 上看到的那样)来定义数学函数,并在某个预定义的范围内绘制该函数。我使用 eval() 函数来解释字符串并填充 y 值列表(已定义的 x 值列表)。我只允许 eval() 访问一些常见的 numpy 数学函数和变量名 'x'。
这 class 允许我为用户输入的每个字符串创建一个对象,并创建两个列表 x 和 y,以便使用 matplotlib 绘图。您可以 运行 这个 MWE 并看到它可以很好地处理 x 的函数(例如 sin(x)、ln(x)、3*x 等)并抛出非数学函数的异常,例如 'foo' 根据需要。但是,给它一个像“3”或“4.00”这样的数字会导致 eval() 不向 self.y 列表中写入任何内容。您可以在代码中的不同点打印 self.y 的形状,并且一旦 eval() 运行s(当输入的字符串是数字时)就会看到 self.y 的形状变成 ().
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
class functionType():
def __init__(self, funcStr, xlo=0.0, xhi=10.0, res=100):
self.x = []
self.y = []
self.xlo = xlo
self.xhi = xhi
self.res = res
self.funcStr = funcStr
self.x = np.linspace(self.xlo, self.xhi, self.res)
self.safe_dict = {'np':np,
'sin':np.sin,
'cos':np.cos,
'tan':np.tan,
'arcsin':np.arcsin,
'arccos':np.arccos,
'arctan':np.arctan,
'sinh':np.sinh,
'cosh':np.cosh,
'tanh':np.tanh,
'arcsinh':np.arcsinh,
'arccosh':np.arccosh,
'arctanh':np.arctanh,
'ln':np.log,
'log10':np.log10,
'log2':np.log2,
'exp':np.exp,
'sqrt':np.sqrt,
'abs':np.fabs,
'x':self.x}
try:
self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict)
except Exception:
raise Exception
def _reMakeData(self):
self.x = np.linspace(self.xlo, self.xhi, self.res)
self.safe_dict['x'] = self.x
self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict)
def setXLow(self, value):
self.xlo = value
self._reMakeData()
def setXHigh(self, value):
self.xhi = value
self._reMakeData()
def setRes(self, value):
self.res = value
self._reMakeData()
def getXLow(self):
return self.xlo
def getXHigh(self):
return self.xhi
def getRes(self):
return self.res
def getData(self):
return self.x, self.y
func = input("gimme a function: ")
try:
plot1 = functionType(func)
x, y = plot1.getData()
plt.plot(x,y,marker='',color='red')
plt.show()
except Exception as e:
print("no good: ",e)
有人看到这里的问题吗?我希望能够处理想要绘制常量函数的用户。需要明确的是,当我给它一个像 4.0 这样的常量时,我希望它将一个列表写入 self.y (它实际上是一个 1D numpy 数组,但我们不必迂腐)与 self.x 填充的长度相同4.0 的。
这不适用于 Web 或服务器应用程序,我完全了解 eval() 固有的风险,所以请不要犹豫使用它:)
问题是绘图需要 y 值列表与 x 值列表的长度相同。如果你输入的表达式涉及x
,这就可以正常工作,因为x
是一个numpy数组,所以对其进行数学运算将产生一个相同长度的数组。但是如果你只是输入一个数字 y
会被设置为一个数字,而不是一个数组。
一种可能是在设置y
后检查它是否是一个numpy数组,如果不是,则假设它是一个数字并重复适当的次数:
if not isinstance(self.y, np.ndarray):
self.y = np.repeat(self.y, len(self.x))
您的代码还有其他一些错误和奇怪的事情。在你传递给 eval
的字典中,你想使用 {'__builtins__': None}
,并在 __builtins__
周围加上引号。另外,您对 try/except 的使用毫无意义。执行 except Exception
后立即执行 raise Exception
没有任何作用,并且隐藏了有关引发何种异常的信息。只需删除 try/except;如果引发异常,它将向上传播,您将看到它是哪种异常。同样,您最后的 try/except 也没有用;它所做的只是打印一条消息,该消息的信息量少于如果您没有捕获异常时将打印的消息。