Python类命名空间内列表推导访问类属性触发NameError问题咨询
报错底层原因
Python 3 中所有推导式(列表、字典、集合推导式)和生成器表达式都拥有独立的嵌套作用域,会按照 局部作用域→闭包作用域→全局作用域→内置作用域 的规则查找变量。
而类定义块的局部作用域属于特殊作用域,不会被嵌套在其内部的推导式/生成器表达式的作用域捕获,推导式查找变量时会直接跳过外层的类定义作用域。
你代码里的FOO1赋值逻辑是直接在类定义作用域内执行,没有进入独立的推导式作用域,所以可以正常读取BAR;而FOO2的列表推导式进入了独立作用域,查找BAR时跳过类定义作用域,在全局作用域也找不到对应变量,就会抛出NameError。
可行实现方案
提供3种无侵入的常用方案:
方案1:替换推导式为普通for循环构造列表
普通for循环没有独立作用域,直接在类定义作用域内执行,可以正常读取同类的其他属性:
class Test: BAR = 'world' FOO1 = "%s" % BAR FOO2 = [] for _ in range(1): FOO2.append("%s" % BAR)
方案2:通过lambda默认参数绑定变量值
lambda的默认参数会在定义阶段(类作用域内)完成求值,可以提前把BAR的值绑定到参数上,推导式直接读取lambda的局部参数即可:
class Test: BAR = 'world' FOO1 = "%s" % BAR FOO2 = (lambda bar=BAR: ["%s" % bar for _ in range(1)])()
方案3:将公共属性提取到全局作用域
如果该属性会被多个类复用,可以提取到全局作用域,推导式可以直接读取全局变量:
BAR = 'world' class Test: FOO1 = "%s" % BAR FOO2 = ["%s" % BAR for _ in range(1)]
内容的提问来源于stack exchange,提问作者Michoel
相关产品推荐
相关产品推荐

