2016-06-25 4 views
4

С x = [1,2,3,4] я могу получить итератор от i = iter(x).Итератор Python и zip

С помощью этого итератора я могу использовать функцию zip для создания кортежа с двумя элементами.

>>> i = iter(x) 
>>> zip(i,i) 
[(1, 2), (3, 4)] 

Даже я могу использовать этот синтаксис для получения тех же результатов.

>>> zip(*[i] * 2) 
[(1, 2), (3, 4)] 

Как это работает? Как работает итератор с zip(i,i) и zip(*[i] * 2)?

+2

'[я] * 2 == [i, i] '/' func (* [i, i]) == func (i, i) ' – falsetru

ответ

7

Итератор похож на поток предметов. Вы можете смотреть только элементы в потоке по одному, и вы только когда-либо имеете доступ к первому элементу. Чтобы посмотреть что-то в потоке, вам нужно удалить его из потока, и как только вы возьмете что-то из верхней части потока, он исчез из потока навсегда.

Когда вы позвоните по номеру zip(i, i), zip сначала смотрит на первый поток и берет товар. Затем он смотрит на второй поток (который, случается, является тем же потоком как первый) и берет элемент. Затем он создает кортеж из этих двух предметов и повторяет это снова и снова, пока в потоке ничего не осталось.

Возможно, будет легче узнать, должен ли я писать функцию zip в чистом питоне (для простоты всего 2 аргумента). Это будет выглядеть примерно так :

def zip(a, b): 
    out = [] 
    try: 
     while True: 
      item1 = next(a) 
      item2 = next(b) 
      out.append((item1, item2)) 
    except StopIteration: 
     return out 

Теперь представьте себе случай, когда вы говорите о том, где a и bявляется тем же объектом. В этом случае мы просто вызываем next дважды на итераторе (i в вашем примере), который будет просто взять первые два элемента из i в последовательности и упаковать их в кортеж.

Как только мы поняли, почему zip(i, i) ведет себя так, как это делается, zip(*([i] * 2)) не слишком сложно. Позволяет читать выражение изнутри ...

[i] * 2 

Это просто создает новый список (длины 2), где оба элемента являются ссылками на итератор i. Так что это то же самое, что и zip(*[i, i]) (удобнее писать, когда вы хотите повторить что-то много больше, чем 2 раза). * распаковка - распространенная идиома в python, и вы можете найти более подробную информацию в the python tutorial.Суть его в том, что python принимает итеративный и «распаковывает» его, как если бы каждый элемент итерабельного был отдельным позиционным аргументом функции. Итак:

zip(*[i, i]) 

делает то же самое, как:

zip(i, i) 

И теперь Боба наш дядя. Мы только что приехали на полный круг, так как zip(i, i) - это начало этой дискуссии.

Этот примерный код определенно упрощен больше, чем только упомянутый, только принимающий 2 аргумента. Например, zip, вероятно, будет вызывать iter на входные аргументы, так что он работает для любых итерацию (не только итераторы), но это должно быть достаточно, чтобы получить точку через ...

+0

Имейте в виду, что [' zip' возвращает список в python2 и итератор в python3] (http://www.diveintopython3.net/porting-code-to-python-3-with-2to3.html#zip). –

0

Каждый раз, когда вы получаете элемент из итератора, он остается в этом месте, а не «перематывается». Таким образом, zip(i, i) получает первый предмет от i, затем второй предмет от i и возвращает его как tuple. Он продолжает делать это для каждой доступной пары, пока итератор не будет исчерпан.

zip(*[i]*2) создает list из [i, i] путем умножения i на 2, а затем распаковывает его с * в крайнее левое положение, которое, по сути, посылает два аргумента i и i к zip, производя тот же результат, что и первый фрагмент.

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