2012-06-12 4 views
5

Оба объекта списка и islice являются итерируемыми, но почему это различие в результате.tee function from itertools library

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() потребности потреблять значения из исходного итератора, если вы начинаете потреблять их из исходного итератора, он не сможет правильно функционировать. В вашем примере списка итерация просто начинается снова. В примере генератора он исчерпан и больше значений не производится.

Это хорошо документирован:

После тройника() сделал раскол, оригинал итерация не должна использоваться в другом месте; в противном случае, итерабельность могла бы быть улучшена без информирования объектов ти.

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

В список ваших постижений, вы хотите заменить r с i1.