2012-06-26 38 views
10

當我注意到我的簡單實現沒有產生正確的結果時,我正在寫一個this question的答案。雖然追捕的錯誤,我注意到以下幾點:爲什麼zip()會刪除我的生成器的值?

In [1]: import itertools 
In [2]: gen = itertools.cycle((0,1,2)) 

In [3]: zip(gen, range(3)) 
Out[3]: [(0, 0), (1, 1), (2, 2)] 

In [4]: zip(gen, range(3)) 
Out[4]: [(1, 0), (2, 1), (0, 2)] 

無論出於何種原因,gennext()方法被調用一個additioinal時間。 爲了說明這一點,我用了以下內容:

class loudCycle(itertools.cycle): 
    def next(self): 
     n = super(loudCycle, self).next() 
     print n 
     return n 

In [6]: gen = loudCycle((0,1,2)) 
In [7]: zip(gen, range(3)) 
0 
1 
2 
0 
Out[7]: [(0, 0), (1, 1), (2, 2)] 

回答

17

這是因爲zip評估迭代from left to right,這意味着,經過三個步驟,它調用next()gen,然後纔在iter(range(3))(或類似的東西),並遭遇一個StopIteration。爲了解決這個問題,使用較短的(有限)迭代作爲最左邊的說法:

In [8]: zip(range(3), gen) 
0 
1 
2 
Out[8]: [(0, 0), (1, 1), (2, 2)] 
7

Your self-answer是完全正確的,並提出了很好的解決方案 - 如果的參數zip一個總是比另一個短。但是,在您不知道哪一個更短的情況下,您可能會發現islice有用。 islice也提供了一個簡單的解決方法,如果你想你的元組中的第一項來自你的生成器。在你的情況,你可以這樣做:

>>> import itertools 
>>> gen = itertools.cycle(('a', 'b', 'c')) 
>>> seq = range(3) 
>>> zip(itertools.islice(gen, len(seq)), seq) 
[('a', 0), ('b', 1), ('c', 2)] 
>>> zip(itertools.islice(gen, len(seq)), seq) 
[('a', 0), ('b', 1), ('c', 2)] 

你的答案可能是在這種情況下更好 - 它肯定更簡單 - 但我想我會添加此作爲補充。

相關問題