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

Вывод

<class '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
codechick

СodeСhick.io - простой и эффективный способ изучения программирования.

2024 ©