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
修补函数,但这没有多大帮助。
答案 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
显然,这些是非常不同的:例如,如果n
为3
且acc
为0,则前者打印called a(3,0)
并返回打印{{1}的函数1}}并返回一个打印called a(2,3)
的函数,并返回打印called a(1,5)
并返回called a(0,6)
的函数,而后者打印6
和called 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