有没有办法编写一个创建和执行代码的Python脚本?

时间:2012-12-10 04:27:39

标签: python

Python中有没有办法在Python脚本中创建Python代码然后执行/测试呢?

我的功能有以下类型的表格(例如)

def f(n):
    if n<=3: return [0, 0, 6, 12][n]
    return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4)

但是我希望能够动态地创建这些类型的函数(或任何任意函数),然后在运行时测试它们的输出(而不是将此函数复制/粘贴到脚本中,然后手动测试它) 。

不确定这是否有意义,请在需要时请求详细说明。我已经研究过eval和exec,但是无法让它们使用整个函数定义,只需要像1 + 2这样的基本语句等。

3 个答案:

答案 0 :(得分:4)

有很多方法可以做这种事情。

如果可以在没有“走出语言”的情况下描述该功能,您可以定义一个本地函数并将其返回,如Blender的答案。当您认为需要定义新函数时,这通常是您想要的(借用Blender的示例):

def make_func(a, b):
    def f(n):
        return n**a + b
    return f

有时,您可以做得更好,并将功能表示为数据。例如,如何创建任意多项式函数?好吧,你不必;你可以有一个泛型多项式函数,它接受一系列系数和一个值并对其进行评估;那么你需要做的就是创建系数列表。

事实上,我认为这是你想要的。正如你所说:

  

可以返回2 * f(n-1) - 4 * f(n-2) - 5 * f(n-3)+ 15 * f(n-4)一分钟,或返回f(n -1)+ 3 * f(n-2)另一个,或f(n-1)+ f(n-2)+ f(n-3)+ f(n-4)+ 5 * f(n-5) )取决于我需要它。

这绝对可以表示为系数列表:

def make_recursive_func(coefficients, baseval):
    def f(n):
        if n < len(coefficients): return baseval[n]
        return sum(coefficient * f(n-i-1) for i, coefficient in enumerate(coefficients))
    return f

但是编写一个eval_recursive_func(coefficients, baseval)可能更简单,如果您对返回的函数所做的只是立即调用它然后忘记它。

有时 - 很少,但不是永远 - 你真的需要动态执行代码。正如Himanshu所说,evalexec和朋友是这样做的方式。例如:

newcode = '''
def f(n):
    if n<=3: return [0, 0, 6, 12][n]
    return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4)
'''
exec(newcode)

现在已经定义了f函数,就像你刚刚这样做了一样:

def f(n):
    if n<=3: return [0, 0, 6, 12][n]
    return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4)

在Py3中它与Py2有点不同,并且根据你想要执行的内容有什么变化,或者你只是想要它执行,评估,编译或者像导入一样处理等等。但这是基本的想法。

如果你想不出为什么要写第一个而不是第二个,那么你就不需要了。

如果你无法弄清楚如何动态生成正确的字符串,你就不应该这样做。

而且,正如Ignacio Vazquez-Abrams指出的那样,如果这些功能可以建立在用户输入之外,那么你需要做一些事情来验证它们是否安全,通常是通过迭代编译和走AST来实现。

最后,更少见的是,你需要使用new模块(和/或inspect)来动态创建一个新的函数对象(或者甚至是手工制作的字节码)。但是如果你需要知道如何做到这一点,你可能已经知道如何做了。

答案 1 :(得分:3)

如果您的功能相似,您可以使用其他功能创建它们:

def make_func(a, b):
    def f(n):
        return n**a + b

    return f

使用make_func转换此函数定义:

def g(n):
     return n**2 + 1

进入这个:

g = make_func(2, 1)

在你的情况下,这样的事情应该有效:

def create_f(start_condition, vars, coeff_pairs):
    def x(n):
        if n <= start_condition:
            return vars[n]

        result = 0.0

        for coeff, shift in coeff_pairs:
            result += coeff * x(n + shift)

        return result

    return x

你可以用:

来调用它
f = create_f(3, [0, 0, 6, 12], [(2, -1), (-4, -2), (-5, -3), (15, -4)])

输出与硬编码功能的输出相匹配。

答案 2 :(得分:2)

这很有道理。 Python甚至为此目的明确地有一个set of modules。确保在执行函数之前先走AST并验证节点,以确保有人没有偷偷进入os.system('rm -rf /')