为什么在列表理解中没有定义一个类变量,而在列表理解中又定义了一个类变量呢?
我刚刚阅读了以下问题的答案:从类定义中的列表理解中访问类变量
I just read the answer to this question: Accessing class variables from a list comprehension in the class definition
这有助于我理解为什么以下代码导致NameError: name 'x' is not defined
:
It helps me to understand why the following code results in 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
.但是我不明白为什么下面的代码能正常工作.
The NameError
occurs because x
is not defined in the special scope for list comprehension. But I am unable to understand why the following code works without any error.
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
也不会在列表理解的范围内定义.范围.
I get the output [0, 1, 2, 3]
. But I was expecting this error: NameError: name 'data' is not defined
because I was expecting just like in the previous example the name x
is not defined in the list comprehension's scope, similarly, the name data
would not be defined too in the list comprehension's scope.
您能不能帮助我理解为什么x
不是在列表理解的范围内定义的,而data
是在列表理解的范围内定义的?
Could you please help me to understand why x
is not defined in the list comprehension's scope but data
is?
data
是列表理解的源;它是传递给创建的嵌套作用域的一个参数.
data
is the source of the list comprehension; it is the one parameter that is passed to the nested scope created.
列表理解中的所有内容都在单独的范围(基本上是作为一个函数)中运行,除了最左边的for
循环中使用的可迭代项.您可以在字节码中看到这一点:
Everything in the list comprehension is run in a separate scope (as a function, basically), except for the iterable used for the left-most for
loop. You can see this in the byte code:
>>> 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
结果执行).
The <listcomp>
code object is called like a function, and iter(data)
is passed in as the argument (CALL_FUNCTION
is executed with 1 positional argument, the GET_ITER
result).
<listcomp>
代码对象将查找该参数:
The <listcomp>
code object looks for that one argument:
>>> 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
调用引用传入的第一个也是唯一的位置参数;之所以在这里未命名,是因为从来没有一个函数定义来为其命名.
The LOAD_FAST
call refers to the first and only positional argument passed in; it is unnamed here because there never was a function definition to give it a name.
在列表理解(或集合或字典理解,或生成器表达式)中使用的其他任何名称都是局部变量,闭包或全局变量,而不是参数.
Any additional names used in the list comprehension (or set or dict comprehension, or generator expression, for that matter) are either locals, closures or globals, not parameters.