匿名函数递归(Python)

首先我们先看一下阶乘函数的递归实现函数,函数主体在定义时并不会运行函数主体而是将函数信息保存至 Frame(也就是栈)中。当函数执行时,函数主体内部用到的 fact(即自己)函数会从 Frame 中查找对应的函数并调用。这样就完成了一个递归函数的实现,从这里我们也能看到,函数是能获取到自身的。

def fact(n: int) -> int:
    if n == 0:
        return 1
    return fact(n - 1) * n

匿名函数递归(CS61A Homeowork3 Q6 Anonymous Factorial),此处指 python 中的 lambda 函数。

而匿名函数因为无法将函数本身信息保存至 Frame 中,因此在执行时无法获取到自身也就无法完成调用(递归)。这个时候就需要我们构造一个特殊的匿名函数完成自调用的过程,也就是对应以下这段特殊代码。以下这段代码实现了最简单的递归阶乘函数。

>>> fact = (lambda f: f(f))(lambda s: lambda x: 1 if x == 1 else s(s)(x - 1) * x)
>>> fact(5)
120

我们这里需要将这个匿名函数拆分为三个部分解读:

  1. (lambda f: f(f))(EXPRESSION):自调用函数,当传入一个函数时,会调用该函数并将该函数作为参数传入其本身。注意,这个函数只会执行一次,也就是只负责将 EXPRESSION 作为函数参数传入函数本身,为 lambda s 实现递归做铺垫。
  2. lambda s: lambda x: EXPRESSION:双层函数,首次调用时会将其主体发送给外层函数,即发送给 1 中的函数,并获取函数 lambda s 自身。此时变量 s 将保存整个 lambda s 函数本身,此时 s 的结构应当为 Callable[[Callable], Callable[int], int]
  3. 1 if x == 1 else s(s)(x - 1) * x):阶乘函数主体,重点在于 s(s)(x - 1)。由于参数 s 的结构为 lambda s 本身,因此需要先将 s 作为变量传入自身后传入 lambda x 的参数才能实现递归(即自调用),否则递归将会终止。剩下的内容实际上与前面的阶乘函数相同不在复述。

通过组合以上三个核心代码,我们就能实现匿名函数递归的功能了。实际上以上代码的核心目的就只有一个,获取函数本身以实现自调用(递归)。

以下是匿名函数的等价表达式:

from typing import Callable


def self_applicator(func: Callable[[Callable], Callable]) -> Callable:
    return func(func)


def inner_function(s: Callable[[Callable], Callable]) -> Callable[[int], int]:
    def factorial(n: int) -> int:
        return 1 if n == 1 else n * s(s)(n - 1)
    return factorial


factorial_calculator = self_applicator(inner_function)
result = factorial_calculator(5)
print(result)


本文经「原本」原创认证,作者乾坤盘,访问yuanben.io查询【SRPXYI91】获取授权信息。

posted @ 2025-05-03 22:13  乾坤盘  阅读(45)  评论(0)    收藏  举报