为何仅在构建非零长度元组时访问类属性foo会失败?
问题解答
这背后的核心原因是生成器表达式的惰性求值特性,以及Python类定义过程中的作用域规则:
生成器表达式的执行时机
bar_ok1 = (foo for _ in range(10))只是创建了一个生成器对象,里面的foo引用并不会立即执行——生成器是惰性的,只有当你迭代它的时候才会去计算每个元素。所以类定义时不会触发foo的查找,自然不会报错。bar_ok2 = tuple(foo for _ in [])中的生成器是空的,tuple()构造时不需要迭代任何元素,因此foo的引用根本不会被执行,也不会报错。
非零长度元组的触发问题
- 当你用
tuple()构造非零长度的生成器(比如bar_fail1和bar_fail2)时,tuple()会立即迭代生成器来生成元素,这时候就会执行foo的引用。 - 而Python的类定义是一个临时的执行环境,生成器表达式的作用域无法访问类定义时的临时命名空间——它只会去全局作用域或者封闭的函数作用域找变量,这两个地方都没有
foo,所以就抛出了NameError。
- 当你用
补充说明:
即使你后续去迭代bar_ok1,同样会触发NameError,因为生成器的作用域规则不会因为类定义完成而改变,它依然找不到foo。如果要在生成器里访问类属性,你可以在类定义完成后通过类名引用,或者用其他方式显式传递作用域。
内容的提问来源于stack exchange,提问作者Semnodime
相关产品推荐
相关产品推荐

