我只是阅读了以下问题的答案:从类定义中的列表理解访问类变量
它有助于我理解为什么以下代码会导致NameError: name 'x' is not defined:
NameError: name 'x' is not defined
class A: x = 1 data = [0, 1, 2, 3] new_data = [i + x for i in data] print(new_data)
NameError发生这种情况是因为x未在列表理解的特殊范围内定义。但是我不明白为什么下面的代码可以正常工作。
NameError
x
class A: x = 1 data = [0, 1, 2, 3] new_data = [i for i in data] print(new_data)
我得到了输出[0, 1, 2, 3]。但是我一直在期待这个错误:NameError: name 'data' is not defined因为我一直在期待,就像在上一个示例中一样,名称x没有在列表理解的范围内定义,类似地,名称data也不会在列表理解的范围内定义。
[0, 1, 2, 3]
NameError: name 'data' is not defined
data
您能不能帮助我理解为什么x列表理解范围内没有定义而是data为什么?
data是列表理解的 来源 ;它是传递给创建的嵌套作用域的一个参数。
列表理解中的所有内容都在单独的范围内运行(基本上是作为一个函数),除了用于最左侧for循环的可迭代对象。您可以在字节码中看到这一点:
for
>>> def foo(): ... return [i for i in data] ... >>> dis.dis(foo) 2 0 LOAD_CONST 1 (<code object <listcomp> at 0x105390390, file "<stdin>", line 2>) 3 LOAD_CONST 2 ('foo.<locals>.<listcomp>') 6 MAKE_FUNCTION 0 9 LOAD_GLOBAL 0 (data) 12 GET_ITER 13 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 16 RETURN_VALUE
的<listcomp>代码对象被称为像的功能,以及iter(data)作为参数(在被传递CALL_FUNCTION与1个位置参数,执行的GET_ITER结果)。
<listcomp>
iter(data)
CALL_FUNCTION
GET_ITER
该<listcomp>代码对象将查找一个参数:
>>> dis.dis(foo.__code__.co_consts[1]) 2 0 BUILD_LIST 0 3 LOAD_FAST 0 (.0) >> 6 FOR_ITER 12 (to 21) 9 STORE_FAST 1 (i) 12 LOAD_FAST 1 (i) 15 LIST_APPEND 2 18 JUMP_ABSOLUTE 6 >> 21 RETURN_VALUE
该LOAD_FAST调用引用传入的第一个也是唯一的位置参数。它在这里未命名,因为从未有函数定义为其命名。
LOAD_FAST
列表推导中使用的任何其他名称(或set或dict推导或生成器表达式)都是局部变量,闭包或全局变量,而不是参数。