替代执行官

时间:2016-08-01 12:44:45

标签: python

我目前正在尝试使用tkinter编写Python(3.4.4)GUI,这应该允许将任意函数适合某些数据点。为了简单起见,我想创建一些输入函数并对其进行评估。之后,我想使用curve_fit中的scipy来绘制并拟合它。

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

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

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

print(buttonfit_press()(4))

这里有一些代码在我开始使用xval之前产生NameError: name 'f' is not defined

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)也不成功......

所以,我的问题是:我可以在这种情况下使用一个很好的替代方案吗?如果没有,我如何使用exec运行代码?

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

@GáborErdős:

要么我不理解,要么我不同意。如果我在主循环中对相同的段进行编码,则会识别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

@ŁukaszRogalski:

打印execstr对我来说似乎很好:

def f(x):
    return x+1

由于我的编辑器不太可能出现缩进错误,但我仔细检查了 - 没关系。 介绍my_locals,在exec中调用它并在之后打印显示:

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

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

@ user3691475:

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

@Dunes:

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我不确定你到底想要做什么,即允许哪些功能,允许哪些操作等等。

以下是带有一个动态参数的函数发生器的示例:

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