拦截返回

时间:2013-02-03 06:46:13

标签: python python-3.x

python中是否有办法拦截(和更改)已编译函数的返回值?

基本思想是:我有一个功能

def a (n, acc):
    if n == 0: return acc
    return a (n - 1, acc + n)

我想修补它,所以它的行为如下:

def a (n, acc):
    if n == 0: return acc
    return lambda: a (n - 1, acc + n)

是否可以编写函数f,例如f (a)会产生第二个代码段中的函数?

如果python可以找到它的源代码然后返回新编译的补丁函数,我可以通过inspect修补函数,但这没有多大帮助。

3 个答案:

答案 0 :(得分:1)

感谢您的投入。我没有看到明显的:

def inject (f):
    def result (*args, **kwargs):
        return lambda: f (*args, **kwargs)
    return result

我接受了大卫的回答,因为他把我推向正确的方向。

答案 1 :(得分:1)

如果我正确理解你想要什么,理论上是不可能的;您似乎要描述的转换是对等效函数产生不同影响的转换,具体取决于源代码的表面细节,这些细节可能不会在编译形式中保留。例如,考虑给定函数的以下两个版本:

def a (n, acc):
    print('called a(%d,%d)' % (n, acc))
    if n == 0: return acc
    return a (n - 1, acc + n)

def a (n, acc):
    print('called a(%d,%d)' % (n, acc))
    if n == 0: return acc
    ret = a (n - 1, acc + n)
    return ret

显然它们在功能上是相同的。在源代码中,唯一的区别是前者直接在某个表达式上使用return,而后者将该表达式的结果保存到局部变量中,然后在该变量上使用return。在编译形式中,根本不需要有任何区别。

现在考虑“修补”版本:

def a (n, acc):
    print('called a(%d,%d)' % (n, acc))
    if n == 0: return acc
    return lambda: a (n - 1, acc + n)

def a (n, acc):
    print('called a(%d,%d)' % (n, acc))
    if n == 0: return acc
    ret = a (n - 1, acc + n)
    return lambda: ret

显然,这些是非常不同的:例如,如果n3acc为0,则前者打印called a(3,0)并返回打印{{1}的函数1}}并返回一个打印called a(2,3)的函数,并返回打印called a(1,5)并返回called a(0,6)的函数,而后者打印6called a(3,0)和{ {1}}和called a(2,3)并返回一个函数,该函数返回一个函数,该函数返回一个返回called a(1,5)的函数。

更广泛的区别在于,每次调用新的返回值时,第一个“修补”函数执行计算的一个步骤,而第二个“修补”版本在初始调用期间执行计算的所有步骤,并且简单地说为娱乐安排一系列后续电话。只要存在副作用(例如打印消息,或者如此深度递归以至于溢出堆栈),这种差异就会很重要。如果调用者引入副作用也可能很重要:请注意,这些函数只会递归,直到其他一些代码重新定义called a(0,6),此时它们之间存在差异。计划继续重新调用6的版本以及已完成所有调用的版本。

由于您无法区分两个“未修补”版本,因此您显然无法生成转换所暗示的独特“修补”版本。

答案 2 :(得分:0)

卢克的答案非常详细,但这可能仍然有用:

>>> def f(*args, **kwargs):
...     return lambda: a(*args, **kwargs)
...
>>> f(10, 0)()
55
相关问题