如果我正确理解你想要什么,理论上是不可能的;您似乎正在描述的转换会对等效函数产生不同的影响,具体取决于可能不会以编译形式保留的源代码的表面细节。例如,考虑给定函数的以下两个版本:
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
很明显,这些是非常不同的:例如,如果nis3并且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的版本与已经完成了所有的调用。
由于您无法区分两个“未打补丁”版本,因此您显然无法生成转换所暗示的不同“打补丁”版本。