2013-12-18 2 views
7

ПочемуВызывающие несколько итераторы на xrange объекты

zip(*[xrange(5)]*2) 

дают [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] но

zip(*[iter(xrange(5))]*2) 

дать [(0, 1), (2, 3)]?

Я всегда, хотя этот генератор был итератором, поэтому iter на генераторе не было.

Например,

list(iter(xrange(5))) 
[0, 1, 2, 3, 4] 

такое же, как

list(xrange(5)) 
[0, 1, 2, 3, 4] 

(То же самое верно и для Python 3, но с list(zip( и range.)

ответ

8

Theres разницу между итерационный и итератор. Вы можете использовать iter(x) для создания итератора для любого заданного итерационного x. Итератор инкапсулирует состояние итерации, а итерабельность - это то, от чего вы можете создать новый итератор.

xrange() - это истребитель, но не итератор. Вы можете создать несколько итераторов для одного объекта xrange(), и каждый из них имеет свою собственную позицию.

Функция zip() неявно вызывает iter() по каждому из своих аргументов. Для zip(*[xrange(5)]*2) это создаст два итератора для тех же объектов xrange(), каждый со своим собственным итерационным состоянием. Для zip(*[iter(xrange(5))]*2) вы уже проходите в том же итераторе дважды. Вызов iter() на итераторе просто возвращает сам итератор, поэтому в этом случае вы получите только один итератор.

+1

Ah hah - объекты xrange неизменяемы и могут повторно повторяться без исчерпания. –

+0

@Peter DeGlopper: Я не думаю, что это имеет какое-то отношение к неизменности, просто тот факт, что '[an_object] * 2' возвращает список с двумя ссылками на тот же объект - в этом вопросе тот же самый итератор. 'range (5)', который возвращает (изменяемый) список, ведет себя так же, как 'xrange (5)' здесь. – crennie

+0

Но есть также две ссылки на один и тот же объект 'xrange' в списке' [xrange (5)] * 2', поэтому, если бы он был фактически итератором, он будет вести себя как ожидаемый OP. Вы правы, что неизменность на самом деле не является ключевым моментом - просто, что итерация по ней не меняет свое состояние. –

Смежные вопросы