リストを理解するためにリスト内包表記をいじっていたところ、説明できない予期せぬ出力に遭遇しました。この質問は以前に聞かれたことはありませんが、/ is /が繰り返し質問される場合は、お、び申し上げます。
私は本質的に、ジェネレータを生成するジェネレータを書き込もうとしていました。リスト内包表記を使用する単純なジェネレーターは次のようになります。
_(x for x in range(10) if x%2==0) # generates all even integers in range(10)
_
私がやろうとしていたことは、2つのジェネレーターを生成するジェネレーターを書くことでした-最初のジェネレーターはrange(10)の偶数を生成し、2番目のジェネレーターはrange(10)の奇数を生成しました。このために、私はやった:
_>>> (x for x in range(10) if x%2==i for i in range(2))
<generator object <genexpr> at 0x7f6b90948f00>
>>> for i in g.next(): print i
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
UnboundLocalError: local variable 'i' referenced before assignment
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> g = (x for x in range(10) if x%2==i for i in range(2))
>>> g
<generator object <genexpr> at 0x7f6b90969730>
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
UnboundLocalError: local variable 'i' referenced before assignment
_
割り当て前に「i」が参照されている理由がわかりません
私はそれがi in range(2)
と何か関係があるかもしれないと思ったので、私はしました:
_>>> g = (x for x in range(10) if x%2==i for i in [0.1])
>>> g
<generator object <genexpr> at 0x7f6b90948f00>
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
UnboundLocalError: local variable 'i' referenced before assignment
_
これは私には意味がありませんでしたので、最初にもっと簡単なものを試すのがベストだと思いました。だから私はリストに戻って試しました:
_>>> [x for x in range(10) if x%2==i for i in range(2)]
[1, 1, 3, 3, 5, 5, 7, 7, 9, 9]
_
私はこれと同じだと思っていました:
_>>> l = []
>>> for i in range(2):
... for x in range(10):
... if x%2==i:
... l.append(x)
...
>>> l
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9] # so where is my list comprehension malformed?
_
しかし、私が思い切って試してみると、これはうまくいきました:
_>>> [[x for x in range(10) if x%2==i] for i in range(2)]
[[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]] # so nested lists in nested list comprehension somehow affect the scope of if statements? :S
_
だから、if
ステートメントがどのレベルのスコープで動作するのかという問題だと思ったので、これを試しました。
_>>> [x for x in range(10) for i in range(2) if x%2==i]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_
そして今、私は完全に混乱しています。誰かがこの動作を説明してください。リストの内包表記が正しくないように見える理由がわかりません。また、if
ステートメントのスコープがどのように機能するのかもわかりません。
PS:質問を校正しながら、これは宿題の質問のように見えることに気付きました-そうではありません。
括弧を使用する必要があります。
((x for x in range(10) if x%2==i) for i in range(2))
これは私には意味がありませんでしたので、最初にもっと簡単なものを試すのがベストだと思いました。だから私はリストに戻って試しました:
[>>> [範囲内のxのx(10)範囲iのx%2 == iの場合] [1、1、3、3、5、5、7、7、9、9]
これは、前のリストの内包表記がi変数を囲んでいるスコープにリークし、現在のスコープのiになるために機能しました。新鮮なpythonインタープリターを起動してみてください。これはNameErrorにより失敗します。カウンターのリーク動作はPython 3.で削除されました。
編集:
Forの同等のループ:
(x for x in range(10) if x%2==i for i in range(2))
だろう:
l = []
for x in range(10):
if x%2 == i:
for i in range(2):
l.append(x)
また、名前エラーが発生します。
EDIT2:
括弧付きバージョン:
((x for x in range(10) if x%2==i) for i in range(2))
以下と同等です:
li = []
for i in range(2):
lx = []
for x in range(10):
if x%2==i:
lx.append(x)
li.append(lx)
Lie Ryanのfor-loopと同等のものは、私を次のように導きます。
[x for i in range(2) for x in range(10) if i == x%2]
出力
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
リー・ライアンの答えを少し広げて:
何か=(範囲(10)のxのx x(範囲(2)のiのx%2 == iの場合))
以下と同等です:
def _gen1():
for x in range(10):
if x%2 == i:
for i in range(2):
yield x
something = _gen1()
一方、括弧で囲まれたバージョンは次と同等です。
def _gen1():
def _gen2():
for x in range(10):
if x%2 == i:
yield x
for i in range(2):
yield _gen2()
something = _gen1()
これにより、実際には2つのジェネレーターが生成されます。
[<generator object <genexpr> at 0x02A0A968>, <generator object <genexpr> at 0x02A0A990>]
残念ながら、出力は消費方法に依存するため、生成されるジェネレーターはやや不安定です。
>>> gens = ((x for x in range(10) if x%2==i) for i in range(2))
>>> for g in gens:
print(list(g))
[0, 2, 4, 6, 8]
[1, 3, 5, 7, 9]
>>> gens = ((x for x in range(10) if x%2==i) for i in range(2))
>>> for g in list(gens):
print(list(g))
[1, 3, 5, 7, 9]
[1, 3, 5, 7, 9]
私のアドバイスは、ジェネレーター関数を完全に記述することです:i
で正しいスコープを取得しようとすることは、ほとんど不可能だと思います。
嘘は構文的な質問に対する答えを持っています。提案:ジェネレーターの本体にあまり詰め込まないでください。関数ははるかに読みやすくなっています。
def make_generator(modulus):
return (x for x in range(10) if x % 2 == modulus)
g = (make_generator(i) for i in range(2))