为什么Python类定义中lambda包裹的MyClass、self合法,直接调用就报错?
Python类作用域下的名称绑定与函数延迟执行特性解答
核心逻辑
所有Python函数(包括lambda匿名函数)都是延迟执行的:函数内部的代码只会在函数被调用时运行,内部引用的变量也只会在调用时才去对应作用域查找,定义阶段不会做变量存在性校验。
1. 类定义的执行规则
Python解析类定义时,会从上到下同步执行类体中的所有代码:
- 类名
MyClass需要等整个类体代码全部执行完成后,才会被绑定到当前作用域的同名变量 self是实例方法的专属入参,只有当实例方法被调用时才会被传入,类定义阶段不存在这个变量
2. 非法代码的报错原因
你给出的报错用例,本质都是代码在类定义阶段直接执行,此时目标变量还未绑定:
# 报错:类定义阶段执行MyClass(),此时MyClass还未完成绑定 class MyClass: children = MyClass()
# 报错:类定义阶段直接调用f(),此时MyClass还未完成绑定 class MyClass: def f(): return MyClass() print(f())
# 报错:类定义阶段不存在self变量 class MyClass: children = self()
3. lambda写法不报错的原理
把代码包进lambda后,只是完成了匿名函数的定义,lambda内部的代码不会立刻执行,因此类定义阶段不会触发变量查找,自然不会报错:
注意:你给出的
lambda: self()仅在定义阶段不报错,如果你实际调用这个lambda,依然会抛出NameError,因为全程没有self变量被注入到该lambda的作用域,这个写法没有实用价值,仅语法层面在定义阶段合法。
只有当lambda被调用时,才会查找对应变量:
class MyClass: # 仅定义lambda,不执行内部代码,类定义阶段无报错 children = defaultdict(lambda: MyClass()) # 类定义完成,MyClass已经绑定到对应变量 mc = MyClass() # 访问不存在的key时才调用lambda,此时MyClass已经存在,正常创建实例 cc = mc.children[0]
4. Trie节点写法的合理性
Trie实现中children = defaultdict(lambda: TrieNode())是非常通用的简洁写法,逻辑完全自洽:
defaultdict的默认工厂函数(即传入的lambda),只会在访问字典不存在的key时才会被触发调用,此时整个TrieNode类早就完成了定义和变量绑定,当然可以正常创建实例。
内容的提问来源于stack exchange,提问作者moon
相关产品推荐
相关产品推荐

