zip
をエミュレートする2つの関数をPython 2.xと3.xで組み込みました。最初のものは、(Pythonの2.xでのような)リストを返し、もう一つは(Pythonの3.xのように)時間に設定された結果の一枚を返すジェネレータ関数である:ジェネレータ式を使用するとPythonがハングする
def myzip_2x(*seqs):
its = [iter(seq) for seq in seqs]
res = []
while True:
try:
res.append(tuple([next(it) for it in its])) # Or use generator expression?
# res.append(tuple(next(it) for it in its))
except StopIteration:
break
return res
def myzip_3x(*seqs):
its = [iter(seq) for seq in seqs]
while True:
try:
yield tuple([next(it) for it in its]) # Or use generator expression?
# yield tuple(next(it) for it in its)
except StopIteration:
return
print(myzip_2x('abc', 'xyz123'))
print(list(myzip_3x([1, 2, 3, 4, 5], [7, 8, 9])))
このうまく機能と内蔵のzip
の予想出力が得られます。
[('a', 'x'), ('b', 'y'), ('c', 'z')]
[(1, 7), (2, 8), (3, 9)]
それから私は(なぜ角括弧[]
を削除することによって、その(ほぼ)同等のジェネレータ式でtuple()
通話中にリストの内包を交換することについて考えジェネレータが反復可能なexpのためにうまくいくべきであるときに、理解を使って一時的なリストを作成するtuple()
、右か?)
しかし、これはPythonをハングさせます。 CtrlC(WindowsのIDLEの場合)を使用して実行が終了しない場合、最終的に(予期される)MemoryError
の例外が数分後に停止します。
(PyScripterを使用して)コードをデバッグすると、ジェネレータ式を使用すると例外が発生しないことが明らかになりました。 myzip_3x()
の第2の実施の呼び出しはタプル(1, 7)
、(2, 8)
、(3, 9)
、(4,)
、(5,)
、()
、()
、()
、...
を生成しながら、myzip_2x()
に上記第1の実施の呼び出しは、res
に空の組を追加し続けます。
何か不足していますか?
最後の注意:its
が、各機能の最初の行(tuple()
呼び出しで使用されている場合)のジェネレータ(its = (iter(seq) for seq in seqs)
を使用)になる場合、同じハング動作が表示されます。
編集:説明のための
おかげ@Blckknghtを、あなたは正しかったです。 This messageは、上記のジェネレータ関数と同様の例を使用して、何が起こっているかについてより詳細を示します。結論として、生成式を使用すると、Python 3.5+でしか動作せず、ファイルの先頭にfrom __future__ import generator_stop
文が必要で、StopIteration
をRuntimeError
に変更する必要があります(リスト内包表記の代わりにジェネレータ式を使用する場合)。
編集2:上記の最後の注意として
:its
は(its = (iter(seq) for seq in seqs)
を使用して)発電機になった場合、それは、単に1つの反復をサポートする - ジェネレータはワンショットイテレータからです。したがって、whileループが最初に実行されたときには使い果たされ、その後のループでは空のタプルだけが得られます。
ループや関数の外でコードを実行して推測を確認できました。 –
このような良い概念の説明をありがとう。 – John