Lambda表达式为何能在实例化前自引用?Python链表实践疑问
问题分析
你这段代码无限输出"a"的核心原因是Python闭包的延迟绑定特性:lambda里引用的stack变量,并不是定义lambda时stack的当前值,而是在lambda被调用时,才会去全局作用域查找stack的最新值。
一步步拆解代码执行逻辑:
- 第一次赋值
stack = lambda: ("c", None):此时stack指向第一个lambda,但后续会被覆盖。 - 第二次赋值
stack = lambda: ("b", stack):这个lambda里的stack并没有绑定当时的第一个lambda,只是记录了要引用stack这个变量。 - 第三次赋值
stack = lambda: ("a", stack):同样,这里的stack只是一个变量引用,此时stack被更新为这个lambda自身。
当进入循环调用stack()时,每次调用的都是第三个lambda,它返回的("a", stack)里的stack就是它自己,所以每次循环都会把stack重新赋值为这个lambda,导致无限输出"a"。
关于你疑惑的“lambda如何引用尚未创建的自身”——其实不是引用尚未创建的自身,而是lambda里的变量是在调用时解析的。当第三次赋值完成后,stack指向了这个lambda,后续调用时,lambda里的stack就指向了自己,形成了循环引用。
正确实现方式
要让每个lambda持有前一个lambda的引用,需要在定义时就把当前的stack值绑定到lambda内部,而非延迟查找。可以用默认参数实现即时绑定:
import itertools stack = lambda: ("c", None) stack = lambda s=stack: ("b", s) stack = lambda s=stack: ("a", s) for _ in itertools.count(): c, stack = stack() print(c)
执行这段代码会得到你预期的输出:
a b c TypeError: 'NoneType' object is not callable
原理是:默认参数的赋值是在lambda定义时完成的,而非调用时。第二个lambda定义时,s被赋值为当时的stack(第一个lambda);第三个lambda定义时,s被赋值为当时的stack(第二个lambda),这样每个lambda返回的都是前一个lambda的引用,链表就能正确遍历到None,触发预期的错误。
内容的提问来源于stack exchange,提问作者Dorian Turba
相关产品推荐
相关产品推荐

