Функция 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