Что iter () делает, чтобы перечислить? - PullRequest
0 голосов
/ 02 мая 2018

У меня есть этот код:

a = ['animal', 'dog', 'car', 'bmw', 'color', 'blue']
a_iter = iter(a)

print(a)
print(a_iter)

print(dict(zip(a,a)))
print(dict(zip(a_iter,a_iter)))

и вывод:

['animal', 'dog', 'car', 'bmw', 'color', 'blue']
<list_iterator object at 0x7f2d98b756d8>
{'dog': 'dog', 'car': 'car', 'animal': 'animal', 'color': 'color', 'blue': 'blue', 'bmw': 'bmw'}
{'car': 'bmw', 'color': 'blue', 'animal': 'dog'}

Я не понимаю, почему почтовый индекс работает с a_iter иначе, чем a. Что делает iter(), список повторяется, так зачем использовать iter()? Может кто-нибудь объяснить мне это с хорошим примером? Я гуглил об этом, но до сих пор не понимаю.

Ответы [ 3 ]

0 голосов
/ 02 мая 2018

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

0 голосов
/ 02 мая 2018

iter(l) возвращает объект итератора для l. Вместе с next(i) его можно использовать для итерации элементов l.

код:

for x in l: print(x)

эквивалентно этому коду, явно использующему итератор:

i = iter(l)
while True:
    try:
        x = next(i)
        print(x)
    except StopIteration:
        break

Обратите внимание, что итератор также может быть пройден с помощью цикла for:

i = iter(l)
for x in i:
    print(x)

zip(a,b) потребляет один элемент из a, b одновременно.

Когда аргумент zip является последовательностью, он создаст для него собственный итератор.

Когда аргумент является итератором, он будет просто потреблять элементы из него.

Когда это один и тот же итератор в обоих аргументах, каждая итерация zip будет использовать один элемент итератора для первого аргумента и один элемент для второго аргумента.

>>> a = [1,2,3,4]
>>> b = [10,20,30,40]

>>> list(zip(a, b)) # zip two lists
[(1, 10), (2, 20), (3, 30), (4, 40)]

>>> list(zip(a, a)) # zip a list with itself
[(1, 1), (2, 2), (3, 3), (4, 4)]

>>> i1 = iter(a)
>>> i2 = iter(a)
>>> list(zip(i1, i2)) # same as above, but with iterators
[(1, 1), (2, 2), (3, 3), (4, 4)]

>>> i = iter(a)
>>> list(zip(i, i)) # same as above, but with the same iterator
[(1, 2), (3, 4)]
0 голосов
/ 02 мая 2018

iter() ничего не делает для списка; list объект имеет метод __iter__, который iter() использует для создания объекта итератора. Этот объект имеет ссылку на исходный список и индекс; каждый раз, когда вы запрашиваете следующее значение в итераторе, значение текущего индекса извлекается и возвращается, и индекс увеличивается.

Вы можете использовать функцию next(), чтобы получить следующее значение от итератора:

>>> a = ['animal', 'dog', 'car', 'bmw', 'color', 'blue']
>>> a_iter = iter(a)
>>> next(a_iter)  # get the next value
'animal'
>>> next(a_iter)  # get the next value
'dog'

Обратите внимание, что вызов next() снова дает вам новое значение. Вы можете сделать это, пока не закончится итератор:

>>> three_more = next(a_iter), next(a_iter), next(a_iter)
>>> next(a_iter)  # last one
'blue'
>>> next(a_iter)  # nothing left
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Объекты итератора списка сохраняют исходный объект списка; изменение объекта списка отразится в значениях итератора, полученных в next():

>>> b = ['foo', 'bar']
>>> b_iter = iter(b)
>>> next(b_iter)
'foo'
>>> b[1] = 'spam'
>>> b
['foo', 'spam']
>>> next(b_iter)
'spam'

zip() запрашивает следующее значение в каждом из своих аргументов, которое предполагается равным iterables ; zip() звонит iter() на них всех. Для объектов итераторов, таких как a_iter, iter(a_iter) возвращает сам итератор (в конце концов, это уже итератор):

>>> iter(a_iter)
<list_iterator object at 0x10e7b6a20>
>>> iter(a_iter) is a_iter
True

Поскольку a_iter будет выдавать значения из исходного списка, по порядку, это означает, что вы получаете парные элементы в словаре, потому что zip() имеет две ссылки на один и тот же объект ; вы фактически создаете (next(a_iter), next(a_iter)) в качестве значения шага итератора для zip(). Если вы передадите две ссылки на a, с другой стороны, zip() вызовет iter() дважды , создав два отдельных объекта итератора , каждый из которых имеет свой собственный индекс отслеживать.

Давайте посмотрим на это подробно. Обратите внимание, что zip() также создает объект итератора, поэтому мы можем убедиться, что вызов next() для zip(), в свою очередь, приводит к тому, что a_iter делает двойной шаг вперед:

>>> a_iter = iter(a)
>>> a_iter_zip = zip(a_iter, a_iter)
>>> a_iter_zip   # a zip object is an iterator too
<zip object at 0x10e7ba8c8>
>>> next(a_iter_zip)  # get next value of a_iter, together with the next value of a_iter
('animal', 'dog')
>>> next(a_iter)  # the a-list iterator was advanced, so now we get 'car'
'car'
>>> next(a_iter_zip)  # now a_iter is at bmw, so we get bmw and color
('bmw', 'color')

Итераторы являются независимыми объектами, каждый из которых имеет свой собственный индекс:

>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a)   # different iterator from a_iter1
>>> next(a_iter1), next(a_iter1)  # what zip() does
('animal', 'dog')
>>> next(a_iter2), next(a_iter2)  # iter2 is independent
('animal', 'dog')

Таким образом, когда вы используете zip(a, a), на самом деле происходит то, что zip() вызывает iter(a) два раза, создавая два новых итератора, и оба используются для создания вывода:

>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a)
>>> a_iter_1_and_2_zip = zip(a_iter1, a_iter2)
>>> next(a_iter_1_and_2_zip)  # values from a_iter1 and a_iter2
('animal', 'animal')
>>> next(a_iter_1_and_2_zip)  # moving in lockstep
('dog', 'dog')
>>> next(a_iter1)   # moving one of these two one step along, to 'car'
'car'
>>> next(a_iter_1_and_2_zip)   # so a_iter1 is one step ahead!
('bmw', 'car')
>>> next(a_iter1)   # another extra step
'color'
>>> next(a_iter_1_and_2_zip)   # so a_iter1 is two steps ahead!
('blue', 'bmw')
...