如果我正确理解你想要什么,理论上是不可能的;您似乎正在描述的转换会对等效函数产生不同的影响,具体取决于可能不会以编译形式保留的源代码的表面细节。例如,考虑给定函数的以下两个版本:
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
is3
并且acc
是 0,那么前者打印called a(3,0)
并返回一个函数,该函数打印called a(2,3)
并返回一个函数,该函数打印called a(1,5)
并返回一个函数,该函数打印called a(0,6)
并返回6
,而后者打印called a(3,0)
andcalled a(2,3)
和called a(1,5)
andcalled a(0,6)
并且返回返回的函数返回的函数返回的函数6
。
更广泛的区别在于,第一个“修补”函数在每次调用新返回值时执行一个计算步骤,而第二个“修补”版本在初始调用期间执行计算的所有步骤,并简单地安排一系列为了娱乐的后续电话。只要有副作用(例如打印消息,或者递归太深以至于溢出堆栈),这种差异就会很重要。调用者是否引入副作用也很重要:请注意,这些函数只会递归,直到其他一些代码重新定义a
,此时计划继续重新调用a
的版本与已经完成了所有的调用。
由于您无法区分两个“未打补丁”版本,因此您显然无法生成转换所暗示的不同“打补丁”版本。