Python类定义中推导式无法引用类属性的原因及替代方案
Python类定义中推导式无法引用类属性的问题解析
正常运行的场景
直接在类属性赋值中引用其他已定义的类属性可以正常执行:
class X: foo = 42 bar = foo + 5 # X.bar == 47
报错场景:推导式中引用类属性
但使用列表(或字典)推导式时,会触发NameError:
class X: foo = 42 bar = [foo + i for i in range(3)] # NameError: name 'foo' is not defined
问题解答
1. 为什么推导式无法获取类定义作用域的局部变量?
Python的类定义有自己的局部作用域,但列表/字典推导式在Python 3里会创建独立的嵌套作用域,这个作用域不会继承类定义阶段的局部命名空间。
直白点说:直接赋值语句是在类的局部作用域内执行的,能直接拿到已经定义的foo;但推导式相当于一个小型匿名函数,它只会向上查找模块级别的变量,看不到类内部的局部属性,所以找不到foo。
2. 推导式中引用类属性的替代方法
这里有几种实用的解决办法:
- 用生成器表达式转列表:生成器表达式不会创建独立作用域,能访问类的局部属性
class X: foo = 42 bar = list(foo + i for i in range(3)) # X.bar 结果是 [42, 43, 44] - 先把类属性存到临时变量:把
foo赋值给局部临时变量,推导式就能访问到class X: foo = 42 _temp_foo = foo bar = [_temp_foo + i for i in range(3)] - 用普通for循环构建列表:避开推导式,直接在类定义里用循环添加元素
class X: foo = 42 bar = [] for i in range(3): bar.append(foo + i) - 类定义完成后再赋值:如果允许的话,等类完全定义好,再通过类名访问属性赋值
class X: foo = 42 X.bar = [X.foo + i for i in range(3)]
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

