假设我在Python中有一个带参数的任意函数f。

def f(x): return 2*x


现在假设我想要一个函数,该函数需要一个函数并返回相同的函数,但沿y轴翻转(如果已绘制)。

显而易见的方法是

def reverse_fn(f): return lambda x, funct=f: funct(-x)


但是,像这样堆叠函数修改函数会在一段时间后破坏最大递归深度,因为结果只是一个调用了另一个函数的函数,而该函数又一直调用更多函数。

在Python中制作函数修改函数的最佳方法是什么,可以在不占用过多调用栈或嵌套函数的情况下反复使用?

最佳答案

一种方法是编辑函数的字节码。这是一项非常先进的技术,而且非常脆弱。因此,请勿将其用于生产代码!

就是说,那里有一个模块,可以精确实现所需的编辑类型。它被称为bytecodehacks,于2000年4月1日首次发布(是的,这是愚人节的玩笑,但完全是功能性的笑话)。我安装的Python 2.7.6稍晚一些版本(自2005年起)运行良好;抓住它from CVS并照常运行setup.py。 (不要使用April2000版本;它不能在较新的Python上运行)。

bytecodehacks基本上实现了许多实用程序例程,这些例程可以编辑一段代码(一个函数,模块,甚至一个函数中的单个块)的字节码。例如,您可以使用它来实现宏。为了修改功能,inline工具可能是最有用的。

这是使用reverse_fn实现bytecodehacks的方法:

from bytecodehacks.inline import inline

def reverse_fn(f):
    def g(x):
        # Note that we use a global name here, not `f`.
        return _f(-x)
    return inline(g, _f=f)


就这样! inline负责将函数f“内联”到g主体中的繁琐事务。实际上,如果f(x)return 2*x,则从reverse_fn(f)返回的函数将等同于return 2*(-x)(其中将不包含任何函数调用)。

现在,bytecodehacks的局限性在于变量重命名(在extend_and_rename中的inline.py中)有点愚蠢。因此,如果您连续应用reverse_fn 1000次,由于局部变量名称的大小将开始爆炸,您的速度将大大降低。我不确定如何解决此问题,但是如果您这样做,它将大大提高重复内联函数的性能。

10-07 13:19
查看更多