Функция iter() в Python — создание объекта-итератора

В этом уроке вы узнаете, как эффективно использовать встроенную функцию iter() в Python и создавать объект-итератор.

Содержание

Что такое функция iter() в Python?

Функция iter() возвращает итератор данного объекта:

iter(object)

Функция iter() требует аргумента, который может быть итерацией или последовательностью. В общем, аргументом объекта может быть любой объект, поддерживающий протокол итерации или последовательности.

Когда вы вызываете функцию iter() для объекта, функция сначала ищет метод __iter__() этого объекта.

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

Следующая блок-схема иллюстрирует, как работает функция iter():

Как работает функция Python iter()

Примеры функции iter() в Python

В следующем примере определяется простой класс Counter и используется функция iter() для получения итератора объекта Counter:

class Counter:
    def __init__(self):
        self.__current = 0


counter = Counter()
iterator = iter(counter)

Это вызовет TypeError, поскольку объект 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)

Iter(callable,sentinel) будет вызывать вызываемый объект при вызове метода next().

Он вернет значение, возвращаемое вызываемым объектом, или вызовет исключение StopIteration, если результат равен значению sentinel.

Давайте рассмотрим пример, чтобы понять, как работает iter(callable, Sentinel).

  • Сначала определите функцию, которая возвращает замыкание:
def counter():
    count = 0

    def increase():
        nonlocal count
        count += 1
        return count

    return increase

Функция counter() возвращает замыкание. И замыкание возвращает новое целое число, начиная с единицы при вызове.

  • Во-вторых, используйте функцию counter() для отображения чисел от 1 до 3:
cnt = counter()

while True:
    current = cnt()
    print(current)
    if current == 3:
        break

Выход:

1
2
3

Чтобы сделать его более универсальным, вместо этого вы можете использовать итератор.

  • В-третьих, определите новый итератор counter:
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() в Python для проверки, является ли объект итерируемым

Чтобы определить, является ли объект итерируемым, вы можете проверить, реализует ли он метод __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 iter'))
print(is_iterable(100))

Выход:

True
True
False
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *