2012-06-12 93 views
5

列表和islice對象都是可迭代的,但爲什麼會在結果中產生這種差異。itertools庫中的tee函數

r = [1, 2, 3, 4]    
i1, i2 = tee(r) 
print [e for e in r if e < 3] 
print [e for e in i2] 
#[1, 2] 
#[1, 2, 3, 4] 


r = islice(count(), 1, 5)   
i1, i2 = tee(r) 
print [e for e in r if e < 3] 
print [e for e in i2] 
#[1, 2] 
#[] 

回答

14

的這裏的問題是,tee()需要從原來的迭代器消耗的值,如果你開始從原來的迭代器消耗他們,這將無法正常工作。在你的列表例子中,迭代只是重新開始。在生成器示例中,它已耗盡,不會生成更多值。

這是有據可查的:

一旦三通()做了一個分裂,可迭代不應該被其他地方使用的原件;否則,可以在沒有通知T恤對象的情況下使迭代得到提前。

Source

編輯說明這一點在列表和發電機之間的區別:

>>> from itertools import islice, count 
>>> a = list(range(5)) 
>>> b = islice(count(), 0, 5) 
>>> a 
[0, 1, 2, 3, 4] 
>>> b 
<itertools.islice object at 0x7fabc95d0fc8> 
>>> for item in a: 
...  print(item) 
... 
0 
1 
2 
3 
4 
>>> for item in a: 
...  print(item) 
... 
0 
1 
2 
3 
4 
>>> for item in b: 
...  print(item) 
... 
0 
1 
2 
3 
4 
>>> for item in b: 
...  print(item) 
... 
>>> 
+0

但是列表對象和islice對象需要表現類似,對嗎? – John

+1

@John不,當你遍歷列表時,你每次都會得到一個新的迭代器,這意味着你仍然可以得到值。當你使用'islice()'時,你會得到一個生成器,它會產生一次值,然後被耗盡。自己嘗試一下 - 只需循環兩次,然後採取行動並循環兩次 - 注意行爲的差異。 –

+0

@John爲了使這兩個例子的行爲類似,使用'r = iter([1,2,3,4])'而不是'r = [1,2,3,4]'。 – clacke

0

在列表解析,你想i1更換r