2016-08-01 92 views
0

我目前正在尝试编写一个Python(3.4.4)图形用户界面与tkinter应该允许适合一些任意功能的数据点。为了简单起见,我想创建一些输入函数并对其进行评估。后来,我想用从scipy进行绘制和拟合。替代执行

为了做到这一点,我想从用户输入字符串中创建一个动态(拟合)函数。我发现并阅读了exec,但人们说(1)使用起来不安全,(2)总是有更好的选择(例如here和许多其他地方)。所以,我想知道在这种情况下会有什么替代方案?

下面是与工作两个嵌套函数的一些示例代码,但它不是动态:

def buttonfit_press(): 
    def f(x): 
     return x+1 
    return f 

print(buttonfit_press()(4)) 

这里是一些代码,引起NameError: name 'f' is not defined之前,我甚至可以开始使用XVAL:

def buttonfit_press2(xval): 
    actfitfunc = "f(x)=x+1" 
    execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1]) 
    exec(execstr) 
    return f 

print(buttonfit_press2(4)) 

types.FunctionType另一种方法在这里讨论(10303248)未成功要么...

小号o,我的问题是:是否有一个很好的选择可以用于这种情况?或者,如果没有,我如何使exec运行代码?

我希望这是可以理解的,不要太模糊。预先感谢您的想法和意见。


@ GABOR鄂尔多斯:

要么我不明白,或者我不同意。如果我在主循环同一段程序代码,它承认f,我可以从execstr执行代码段:

actfitfunc = "f(x)=x+1" 
execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1]) 
exec(execstr) 
print(f(4)) 
>>> 5 

@卢卡斯Rogalski:

印刷execstr似乎没什么问题:

def f(x): 
    return x+1 

缩进错误不太可能是由于我的编辑器,但我仔细检查过 - 没关系。 介绍my_locals,称其为exec和印刷在事后表示:

{'f': <function f at 0x000000000348D8C8>} 

但是,我仍然得到NameError: name 'f' is not defined


@ user3691475:

你举的例子非常相似,我的第一个例子。但是在我的理解中,这不是“动态的”,即在代码运行时不能改变函数的输出。


@Dunes:

我认为这是朝着正确的方向,谢谢。但是,我不明白我如何评估和使用此功能在下一步?我的意思是:为了能够适应它,我必须提取拟合变量(即f(x)=a*x+b中的a)或评估不同x值的函数(即print(f(3.14)))。

+0

@GáborErdős技术上它是,因为Exec将隐含引用传递'全局()'和'当地人()'和输入参数,他们会突变。 –

+0

@nostradamus你的代码应该可以正常工作。你的缩进是否正确?你可以运行:'my_locals = {}; exec(execstr,globals(),my_locals)'然后显示存储在'my_locals'中的内容?通过打印'execstr'进行完整性检查也不会造成任何影响。 –

回答

0

我不知道究竟是你想干什么,即允许哪些功能,允许什么操作等

这里是一个函数发生器的一个动态参数的例子:

>>> def generator(n): 
     def f(x): 
      return x+n 
     return f 
>>> plus_one=generator(1) 
>>> print(plus_one(4)) 
5 
1

exec/eval的问题是它们可以执行任意代码。因此,要使用execeval,您需要仔细解析代码片段以确保它不包含恶意代码(难以置信的艰巨任务),或者确保代码的来源可信。如果你正在制作一个个人使用的小程序,那很好。一个负责敏感数据或金钱的大计划绝对不是。看起来你的用例被视为具有可信来源。

如果您只想在运行时创建任意函数,那么只需使用lambda表达式和eval的组合。例如。

func_str = "lambda x: x + 1" # equates to f(x)=x+1 
func = eval(func_str) 
assert func(4) == 5 

之所以你尝试不工作是locals(),在功能的情况下,造成局部名字空间的副本。生成字典的变异不会影响当前的本地名称空间。你需要做的是这样的:

def g(): 
    src = """ 
def f(x): 
    return x + 1 
    """ 
    exec_namespace = {} # exec will place the function f in this dictionary 
    exec(src, exec_namespace) 
    return exec_namespace['f'] # retrieve f