I just read the answer to this question: Accessing class variables from a list comprehension in the class definition
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)
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)
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.
Could you please help me to understand why x
is not defined in the list comprehension's scope but data
is?
data
is the source of the list comprehension; it is the one parameter that is passed to the nested scope created.
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
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).
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
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.
来源:https://stackoverflow.com/questions/22692227/why-is-one-class-variable-not-defined-in-list-comprehension-but-another-is