それは完全にうまくいきます:
>>> import pdb
>>> def f(seq):
... pdb.set_trace()
...
>>> f([1,2,3])
--Return--
> <stdin>(2)f()->None
(Pdb) [x for x in seq]
[1, 2, 3]
(Pdb) [x in seq for x in seq]
[True, True, True]
あなたが実際に何をしているのかを示さなければ、あなたの特定のケースでなぜNameError
.
TL;DR python3 では、リスト内包表記は実際には独自のスタック フレームを持つ関数であり、内部スタック フレームからseq
の引数である変数にアクセスすることはできません。代わりに、グローバルtest
として扱われます(したがって、見つかりません)。
ご覧のとおり、python2 と python3 ではリスト内包表記の実装が異なります。Python 2 では、リスト内包表記は実際にはfor
ループの省略形であり、バイトコードでこれを明確に確認できます。
>>> def test(): [x in seq for x in seq]
...
>>> dis.dis(test)
1 0 BUILD_LIST 0
3 LOAD_GLOBAL 0 (seq)
6 GET_ITER
>> 7 FOR_ITER 18 (to 28)
10 STORE_FAST 0 (x)
13 LOAD_FAST 0 (x)
16 LOAD_GLOBAL 0 (seq)
19 COMPARE_OP 6 (in)
22 LIST_APPEND 2
25 JUMP_ABSOLUTE 7
>> 28 POP_TOP
29 LOAD_CONST 0 (None)
32 RETURN_VALUE
バイトコードにFOR_ITER
ループが含まれていることに注意してください。一方、python3 では、リスト内包表記は実際には独自のスタック フレームを持つ関数です。
>>> def test(): [x in seq2 for x in seq]
...
>>> dis.dis(test)
1 0 LOAD_CONST 1 (<code object <listcomp> at 0xb6fef160, file "<stdin>", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (seq)
9 GET_ITER
10 CALL_FUNCTION 1
13 POP_TOP
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
ご覧のとおり、FOR_ITER
ここにはありませんが、代わりに aMAKE_FUNCTION
とCALL_FUNCTION
bytecodes があります。リスト内包表記のコードを調べると、バインディングがどのように設定されているかを理解できます。
>>> test.__code__.co_consts[1]
<code object <listcomp> at 0xb6fef160, file "<stdin>", line 1>
>>> test.__code__.co_consts[1].co_argcount # it has one argument
1
>>> test.__code__.co_consts[1].co_names # global variables
('seq2',)
>>> test.__code__.co_consts[1].co_varnames # local variables
('.0', 'x')
これ.0
が関数の唯一の引数です。x
はループのローカル変数でありseq2
、グローバル変数です。リスト内包表記の引数 は、それ自体ではなく、.0
から取得した iterable であることに注意してください。(上記の出力のオペコードを参照してください)。これは、より複雑な例でより明確になります。seq
seq
GET_ITER
dis
>>> def test():
... [x in seq for x in zip(seq, a)]
...
>>> dis.dis(test)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0xb7196f70, file "<stdin>", line 2>)
3 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (zip)
9 LOAD_GLOBAL 1 (seq)
12 LOAD_GLOBAL 2 (a)
15 CALL_FUNCTION 2
18 GET_ITER
19 CALL_FUNCTION 1
22 POP_TOP
23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> test.__code__.co_consts[1].co_varnames
('.0', 'x')
.0
ここで、常に で示されるリスト内包表記の唯一の引数は、 から取得した iterableであることがわかりますzip(seq, a)
。seq
そしてa
それ自体はリスト内包表記に渡されません。リスト内包内でのみiter(zip(seq, a))
渡されます。
もう 1 つ確認しなければならない点は、 を実行するpdb
と、定義したい関数から現在の関数のコンテキストにアクセスできないということです。たとえば、次のコードは python2 と python3 の両方で失敗します。
>>> import pdb
>>> def test(seq): pdb.set_trace()
...
>>> test([1,2,3])
--Return--
> <stdin>(1)test()->None
(Pdb) def test2(): print(seq)
(Pdb) test2()
*** NameError: global name 'seq' is not defined
test2
変数を定義するとグローバルseq
変数として扱われるため失敗しますが、実際には関数内のローカル変数であるため、アクセスできません。test
表示される動作は、次のシナリオに似ています。
#python 2 no error
>>> class A(object):
... x = 1
... L = [x for _ in range(3)]
...
>>>
#python3 error!
>>> class A(object):
... x = 1
... L = [x for _ in range(3)]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in A
File "<stdin>", line 3, in <listcomp>
NameError: global name 'x' is not defined
最初のものは、次のものとほぼ同等であるため、エラーは発生しません。
>>> class A(object):
... x = 1
... L = []
... for _ in range(3): L.append(x)
...
リスト内包表記はバイトコードで「展開」されているためです。Python3 では、実際に関数を定義しており、ネストされた関数スコープからクラス スコープにアクセスできないため、失敗します。
>>> class A(object):
... x = 1
... def test():
... print(x)
... test()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in A
File "<stdin>", line 4, in test
NameError: global name 'x' is not defined
genexp は python2 の関数として実装されていることに注意してください。実際、それらと同様の動作が見られます (python2 と python3 の両方で):
>>> import pdb
>>> def test(seq): pdb.set_trace()
...
>>> test([1,2,3])
--Return--
> <stdin>(1)test()->None
(Pdb) list(x in seq for x in seq)
*** Error in argument: '(x in seq for x in seq)'
ここでpdb
は詳細を説明しませんが、まったく同じ理由で失敗が発生します。
結論として、これはバグではpdb
なく、python がスコープを実装する方法です。私の知る限り、これを変更してあなたがやろうとしていることを許可するには、pdb
関数の処理方法に大きな変更が必要であり、インタープリターを変更せずにこれを実行できるかどうかはわかりません。
ネストされたリスト内包表記を使用する場合、ネストされたループは python2 のリスト内包表記のようにバイトコードで展開されることに注意してください。
>>> import dis
>>> def test(): [x + y for x in seq1 for y in seq2]
...
>>> dis.dis(test)
1 0 LOAD_CONST 1 (<code object <listcomp> at 0xb71bf5c0, file "<stdin>", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (seq1)
9 GET_ITER
10 CALL_FUNCTION 1
13 POP_TOP
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
>>> # The only argument to the listcomp is seq1
>>> import types
>>> func = types.FunctionType(test.__code__.co_consts[1], globals())
>>> dis.dis(func)
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 29 (to 38)
9 STORE_FAST 1 (x)
12 LOAD_GLOBAL 0 (seq2)
15 GET_ITER
>> 16 FOR_ITER 16 (to 35)
19 STORE_FAST 2 (y)
22 LOAD_FAST 1 (x)
25 LOAD_FAST 2 (y)
28 BINARY_ADD
29 LIST_APPEND 3
32 JUMP_ABSOLUTE 16
>> 35 JUMP_ABSOLUTE 6
>> 38 RETURN_VALUE
ご覧のとおり、バイトコード forlistcomp
には明示的なFOR_ITER
over がありseq2
ます。この明示FOR_ITER
は listcomp 関数内にあるため、スコープに関する制限は引き続き適用されます (たとえばseq2
、グローバルとしてロードされます)。
実際、これを確認するには、次を使用しpdb
ます。
>>> import pdb
>>> def test(seq1, seq2): pdb.set_trace()
...
>>> test([1,2,3], [4,5,6])
--Return--
> <stdin>(1)test()->None
(Pdb) [x + y for x in seq1 for y in seq2]
*** NameError: global name 'seq2' is not defined
(Pdb) [x + y for x in non_existent for y in seq2]
*** NameError: name 'non_existent' is not defined
The NameError
is aboutseq2
と not seq1
(関数の引数として渡される) に注意し、最初の iterable 名を存在しないものに変更すると がどのように変更されるかに注意してくださいNameError
(つまり、最初のケースseq1
では正常に渡されたことを意味します)。