Source: Python iterators

← Rendered

markdown source:

---
description: Как сделать итератор в python
tags: python-standart-library python
title: Python iterators
---
Итераторы в python реализуют метод `__iter__` и могут реализовать метод `__next__`. `__iter__` должен всегда возвращать `self`, а `__next__` может возвращать некое значение.

В данном примере мы получаем бесконечный итератор, который возвращает порядковый номер итерации

```python
>>> class Count:

...     def __iter__(self):
...         self.count = 1
...         return self

...     def __next__(self):
...         x = self.count
...         self.count += 1
...         return x

>>> c = Count()
>>> count = iter(c)
>>> print(next(count))
1
>>> print(next(count))
2
```

Встроенные функции `next()` и `iter()` позволяют получить итератор и извлечь значение. В цикле `for..if` это происходит неявно:

```python
>>> for i in c:
>>>     if i < 10:
>>>         print(i)
1
...
9
```

В данном случае итератор был создан заново. Обратите внимание на условие, которое пришлось задать в цикле - без этого условия нам бы пришлось упереться в бесконечную итерацию. Чтобы решить эту логическую проблему, метод `__next__` может поднимать исключение, если мы достигли граничного условия. Перепишем пример:

```python
>>> class Count:

...     def __iter__(self):
...         self.count = 1
...         return self

...     def __next__(self):
...         x = self.count
...         if count < 10:
...             self.count += 1
...             return x
...         else:
...             raise StopIteration

>>> c = Count()
>>> for i in c:
>>>     print(i)
1
...
9
```

Отлично, итератор остановился там где надо, к тому же `for...in` самостяотельно обработал исключение. Если же мы попробуем сделать это через `next()`, то вот что будет:

```python
...
8
>>> print(next(count))
9
>>> print(next(count))
Traceback (most recent call last):
...
StopIteration
```

Более сложные итераторы могут уметь возвращать себя в виде списка, иметь длину и т.д. Смотри [подробности тут](https://docs.python.org/3/reference/datamodel.html#emulating-container-types)

Основное преимущество итераторов - они вычисляют значения по запросу. Таким образом не требуется вычислит ьвсю последовательность или отображение сразу, что экономит память.

Чтобы облегчить страдания программистов, в python добавлен синтаксис `yield`, который превращает функцию в генератор, возвращающий итератор генератора. В отличие от обычной функции с `return`, которая имеет одну точку входа и после возвращения значения забывает свое состояние, такой итератор будет помнить последнее состояние и при каждом вызове возобновлять работу с той точки, в которой остановился. Подробнее смотри тут: [[python-datamodel]]. Для асинхронных вызовов реализованы исинхронные генераторы через `__aiter__` и `__anext__`.

Смотри еще:

- [[python-glossary]]
- [[python-datamodel]]
- [[python-standart-library]]
- [[asyncio]]


[python-datamodel]: ../lists/python-datamodel "Python datamodel"
[python-glossary]: python-glossary "Python glossary"
[python-standart-library]: ../lists/python-standart-library "Стандартная библиотека python и полезные ресурсы"
[asyncio]: asyncio "Asyncio"