Ответ 1
Они повторяемы, но они не являются итераторами. Они могут быть переданы в iter()
, чтобы получить итератор для них либо неявно (например, через for
), либо явно, но они сами не являются итераторами.
Я изучаю Alex Marteli Python в двух словах, и книга предполагает, что любой объект, который имеет метод next()
, (или, по крайней мере, может быть использован как) итератор. Он также предполагает, что большинство итераторов построены неявными или явными вызовами метода под названием iter
.
Прочитав это в книге, я почувствовал желание попробовать. Я запустил интерпретатор python 2.7.3 и сделал следующее:
>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for number in range(0, 10):
... print x.next()
Однако результат был следующим:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'list' object has no attribute 'next'
В замешательстве я попытался изучить структуру объекта x через dir(x)
, и я заметил, что он имеет объект функции __iter__
. Поэтому я понял, что он может использоваться как итератор, если он поддерживает этот тип интерфейса.
Итак, когда я попробовал еще раз, на этот раз несколько иначе, пытаясь сделать это:
>>> _temp_iter = next(x)
Я получил эту ошибку:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator
Но как список NOT может быть итератором, поскольку он, кажется, поддерживает этот интерфейс и может быть определенно использован как один в следующем контексте:
>>> for number in x:
... print x
Может ли кто-нибудь помочь мне прояснить это в моем сознании?
Они повторяемы, но они не являются итераторами. Они могут быть переданы в iter()
, чтобы получить итератор для них либо неявно (например, через for
), либо явно, но они сами не являются итераторами.
Вам нужно сначала преобразовать список в итератор, используя iter()
:
In [7]: x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [8]: it=iter(x)
In [9]: for i in range(10):
it.next()
....:
....:
Out[10]: 0
Out[10]: 1
Out[10]: 2
Out[10]: 3
Out[10]: 4
Out[10]: 5
Out[10]: 6
Out[10]: 7
Out[10]: 8
Out[10]: 9
In [12]: 'next' in dir(it)
Out[12]: True
In [13]: 'next' in dir(x)
Out[13]: False
проверка, является ли объект итератором или нет:
In [17]: isinstance(x,collections.Iterator)
Out[17]: False
In [18]: isinstance(x,collections.Iterable)
Out[18]: True
In [19]: isinstance(it,collections.Iterable)
Out[19]: True
In [20]: isinstance(it,collections.Iterator)
Out[20]: True
На всякий случай вы сбиты с толку о том, какая разница между итерами и итераторами. Итератор представляет собой объект, представляющий поток данных. Он реализует протокол итератора:
__iter__
методnext
методПовторные вызовы итераторы next() возвращают последовательные элементы в потоке. когда больше нет данных, объект итератора исчерпан, и любые дальнейшие обращения к его next() просто снова вызовет StopIteration.
С другой стороны, итеративные объекты реализуют метод __iter__
, который при вызове возвращает итератор, который допускает многократные проходы над их данными. Итерируемые объекты многоразовые, после исчерпания их можно повторить снова. Они могут быть преобразованы в итераторы с помощью функции iter
.
Итак, если у вас есть список (iterable), вы можете сделать:
>>> l = [1,2,3,4]
>>> for i in l:
... print i,
1 2 3 4
>>> for i in l:
... print i,
1 2 3 4
Если вы преобразуете свой список в итератор:
>>> il = l.__iter__() # equivalent to iter(l)
>>> for i in il:
... print i,
1 2 3 4
>>> for i in il:
... print i,
>>>
Список не является итератором, но в списке содержится объект-итератор __iter__
, поэтому, когда вы пытаетесь использовать для цикла в любом списке, для вызова циклов метод __iter__
и получает объект итератора, а затем он использует метод next() списка.
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
it = x.__iter__()
Теперь it
содержит объект итератора x
, который вы можете использовать как it.next()
до тех пор, пока не будет исключено исключение StopIteration