2017-05-08 5 views
1

私はPythonのジェネレータ、イテレータ、iterablesを学習しています。なぜ次のものが動作しないのか説明できません。私は、エクササイズとして関数zipの簡単なバージョンを作成したいと考えています。ここに私がやったことだ:ジェネレータのStopIteration

def myzip(*collections): 

    iterables = tuple(iter(collection) for collection in collections) 

    yield tuple(next(iterable) for iterable in iterables) 

test = myzip([1,2,3],(4,5,6),{7,8,9}) 

print(next(test)) 
print(next(test)) 
print(next(test)) 

私は何をすることです:

  • 私はcollectionsを持っている私は、コレクションごとに新しいタプルiterables、(作成いくつかのコレクションのタプル
  • ありますiterable)を使用して、イテレータを取得します。iter
  • 次に、各繰り返しで、nextという新しいタプルを作成します。このタプルは次に収穫です。

最初の実行時にオブジェクトiterablesが作成(および保存)されることが期待されます。その後、各繰り返し(最初のものを含む)で、私はnextを呼び出す前にすべてのiterableを呼び出して、それを返します。

しかし、これは私が得るものです:

(1, 4, 8) 
--------------------------------------------------------------------------- 
StopIteration        Traceback (most recent call last) 
<ipython-input-108-424963a58e58> in <module>() 
     8 
     9 print(next(test)) 
---> 10 print(next(test)) 

StopIteration: 

は、だから私は、最初の繰り返しで結構ですし、結果が正しいことがわかります。しかし、2回目の反復ではStopIteration例外が発生します。理由はわかりません。各反復可能にはまだ値があるため、nextのどれもStopIterationを返しません。実際には、これは動作します:

def myziptest(*collections): 

    iterables = tuple(iter(collection) for collection in collections) 

    for _ in range(3): 
     print(tuple(next(iterable) for iterable in iterables)) 

test = myziptest([1,2,3],(4,5,6),{7,8,9}) 

出力:

(1, 4, 8) 
(2, 5, 9) 
(3, 6, 7) 

だから何が起こっているの? どうもありがとう

答えて

1

は、ここでは、このコードとあなたの違いは、あなたのコードだけ1つの結果を得られることである作業溶液

def myzip(*collections): 

    iterables = tuple(iter(collection) for collection in collections) 

    while True: 
     try: 
      yield tuple([next(iterable) for iterable in iterables]) 
     except StopIteration: 
      # one of the iterables has no more left.     
      break 

test = myzip([1,2,3],(4,5,6),{7,8,9}) 

print(next(test)) 
print(next(test)) 
print(next(test)) 

です。意味は、次のを2回以上呼び出すと、StopIterationが与えられます。

yield xは、キューにxを入れて、nextをそのキューからポップすると考えてください。空のキューからポップしようとすると、Stopiterationが返されます。あなたはあなたが入れた数だけポップすることができます。

+0

これは本当に愚かな間違いだった...私はサイクルを追加するのを忘れていたので、関数が最初のnext()の後ではっきりと死んだ。 ありがとうございます! – edoedoedo

+1

問題ありません。参考までに、コレクションが同じサイズでなくても、 'tuple(iterable in iterables in iterables) 'は引き続き動作します。それを 'tuple(iterableでiterableのためのnext(iterable))'にするとStopIterationがトリガーされるので、最短の共通長で停止することができます。 – algrebe

+0

実際、テスト中であれば、print(i) '私は無限ループを起こします。違いは何ですか? – edoedoedo

関連する問題