Функция iter() в Python
В этой статье вы узнаете, как эффективно использовать встроенную функцию iter() в Python.
Функция iter() возвращает итератор заданного объекта:
iter(объект)
Аргументом функции iter() должен быть итерируемый объект или последовательность. В общем случае аргументом может быть любой объект, поддерживающий протокол итерации или последовательности.
Когда вы вызываете функцию iter() для определенного объекта, функция сначала ищет метод __iter__() этого объекта.
- Если метод
__iter__()существует, функцияiter()вызывает его для получения итератора. В противном случае функцияiter()будет искать метод__getitem__(). - Если метод
__getitem__()существует, функцияiter()создаст объект итератора и вернет этот объект. - В противном случае возникает исключение TypeError.

Пример использования iter()
Давайте создадим простой класс Counter и используем функцию iter() для получения итератора объекта counter:
class Counter:
def __init__(self):
self.__current = 0
counter = Counter()
iterator = iter(counter)
Объект Counter не является итерируемым объектом, поэтому возникнет исключение TypeError: 'Counter' object is not iterable.
Теперь добавим метод __getitem__() в класс Counter:
class Counter:
def __init__(self):
self.current = 0
def __getitem__(self, index):
if isinstance(index, int):
self.current += 1
return self.current
Поскольку в Counter есть метод __getitem__(), который возвращает элемент на основе индекса, он является последовательностью.
Теперь вы можете использовать функцию iter(), чтобы получить итератор counter:
counter = Counter()
iterator = iter(counter)
print(type(iterator))
Вывод
В этом случае Python создает объект-итератор и возвращает его. Следовательно, вы можете использовать объект итератора для перебора counter:
for _ in range(1, 4):
print(next(iterator))
Теперь давайте класс CounterIterator к классу Counter и реализуем протокол итерируемого объекта:
class Counter:
def __init__(self):
self.current = 0
def __getitem__(self, index):
if isinstance(index, int):
self.current += 1
return self.current
def __iter__(self):
return self.CounterIterator(self)
class CounterIterator:
def __init__(self, counter):
self.__counter = counter
def __iter__(self):
return self
def __next__(self):
self.__counter.current += 1
return self.__counter.current
Как это работает
- В классе
Counterесть метод__iter__(), который возвращает итератор. Возвращаемый итератор является новым экземпляромCounterIterator. - Класс
CounterIteratorподдерживает протокол итераторов, реализуя методы__iter__()и__next__().
Когда существуют оба метода __iter__() и __getitem__(), функция iter() всегда использует метод __iter__():
counter = Counter()
iterator = iter(counter)
print(type(iterator))
Вывод
<class '__main__.Counter.CounterIterator'>
1
2
3
В этом примере функция iter() вызывает метод __iter__() вместо метода __getitem__(). Поэтому в выводе вы видите итератор CounterIterator.
Вторая форма функции iter()
Функцию iter() можно использовать и так:
iter(callable, sentinel)
callable— вызываемый объект,sentinel— специальное значение, которое используется для представления конца последовательности.
Функция iter(callable, sentinel) вызовет callable-переменную, когда будет вызван метод next().
Функция вернет значение, возвращенное вызываемой переменной, или вызовет исключение StopIteration, если результат будет равен значению sentinel.
Давайте рассмотрим, как работает iter(callable, sentinel), на конкретном примере.
1. Сначала создадим функцию, которая возвращает замыкание:
def counter():
count = 0
def increase():
nonlocal count
count += 1
return count
return increase
Функция counter() возвращает замыкание. А замыкание при вызове возвращает новое целое число, начиная с единицы.
2. Используем функцию counter(), чтобы показать числа от 1 до 3:
cnt = counter()
while True:
current = cnt()
print(current)
if current == 3:
break
Вывод
1
2
3
Чтобы сделать ее более общей, вместо нее можно использовать итератор.
3. Определим новый итератор счетчика:
class CounterIterator:
def __init__(self, fn, sentinel):
self.fn = fn
self.sentinel = sentinel
def __iter__(self):
return self
def __next__(self):
current = self.fn()
if current == self.sentinel:
raise StopIteration
return current
Конструктор CounterIterator принимает вызываемую fn и sentinel.
Метод __next__() возвращает значение, возвращаемое вызываемой переменной fn, или вызывает исключение StopIteration, если возвращаемое значение равно sentinel.
Вот, как использовать итератор CounterIterator:
cnt = counter()
iterator = CounterIterator(cnt, 4)
for count in iterator:
print(count)
Вывод
1
2
3
Вместо того чтобы определять новый итератор каждый раз, когда вы хотите перебрать значения, возвращаемые вызываемой переменной, вы можете использовать функцию iter(callable, sentinel):
cnt = counter()
iterator = iter(cnt, 4)
for count in iterator:
print(count)
Вывод
1
2
3
iter(), чтобы проверить, является ли объект итерируемым
Чтобы определить, является ли объект итерируемым, можно проверить, реализует ли он метод __iter__() или __getitem__().
Однако вы можете использовать функцию iter(), чтобы проверить, является ли объект итерируемым, следующим образом:
def is_iterable(object):
try:
iter(object)
except TypeError:
return False
else:
return True
Если у объекта нет ни метода __iter__(), ни метода __getitem__(), функция iter() вызывает исключение TypeError.
Ниже показано, как использовать функцию is_iterable():
print(is_iterable([1, 2, 3]))
print(is_iterable('Итератор Python'))
print(is_iterable(100))
Вывод
True
True
False
Закрепите практикой
Задачи с автоматической проверкой — решайте прямо здесь, не уходя из учебника.