Ітератори

Модуль 1: Python Core
Рівень 11 , Лекція 4
Відкрита

5.1 Iterable і Iterator

Як ти вже знаєш, ітератори — це об'єкти, які реалізують протокол ітератора, дозволяючи послідовно отримувати елементи з колекції. Ітератори широко використовуються в Python для перегляду елементів послідовностей таких як списки, кортежі і строки.

Розглянемо, як влаштовані ітератори і як їх використовувати.

Ітеруємий об'єкт (Iterable)

Щоб по об'єкту можна було пройтися за допомогою циклу for, він має бути ітеруємим – Iterable. Це означає, що наш об'єкт повинен реалізувати метод __iter__(), який повертає об'єкт-ітератор.

Об'єкт-ітератор (Iterator)

Це спеціальний об'єкт, який має функцію __next__() для повернення наступного елемента послідовності. Коли елементи закінчуються, метод __next__() викликає виключення StopIteration як знак припинення ітерації.

Ітератор також повинен реалізувати метод __iter__(), який повертає сам ітератор.

Приклад з використанням вбудованих функцій Python

У цьому прикладі список numbers є ітеруємим об'єктом. Ми отримуємо ітератор за допомогою функції iter() і використовуємо функцію next() для перегляду елементів до того моменту, поки не буде викликано виключення StopIteration.


# Ітеруємий об'єкт
numbers = [1, 2, 3, 4, 5]
            
# Отримуємо ітератор з ітеруємого об'єкта
iterator = iter(numbers)
            
# Використовуємо ітератор для перегляду елементів
try:
    while True:
        number = next(iterator)
        print(number)
except StopIteration:
    pass
        

Саме це й відбувається, коли ти пишеш код типу:


# Ітеруємий об'єкт
numbers = [1, 2, 3, 4, 5]
            
for number in numbers:
    print(number)
        

5.2 Суть ітератора

Ітератор — це певний об'єкт, який допомагає нам послідовно обійти групу елементів. Реалізації його можуть бути найрізноманітніші. Давай напишемо свій клас, де реалізуємо всі вимоги, що ставляться до ітератора.

Крок 1. Спочатку створимо свій клас

Нехай він по черзі повертає числа від start до end


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        

Крок 2. Підтримка функції __iter__

Тепер нам потрібно додати йому функцію __iter__, яка буде повертати об'єкт-ітератор, у якого буде викликатися функція __next()__. Ми будемо повертати посилання на свій же об'єкт – це не заборонено.


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        

Крок 3. Підтримка функції __next__

Тепер треба додати до нашого об'єкта-ітератора функцію __next__, яка буде повертати черговий елемент нашого списку. Ми просто будемо використовувати змінну current


def __next__(self):
    current = self.current
    self.current += 1
    return current
        

Крок 4. Зупинка ітератора

Якщо ітератор повернув вже всі значення, які планував, він повинен кинути виключення StopIteration. Давайте трохи підправимо нашу останню функцію:


def __next__(self):
    if self.current >= self.end: raise StopIteration
    current = self.current
    self.current += 1
    return current
        

Відмінно. Тепер можна користуватися нашим ітератором. Ось приклад всього нашого коду:


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        current = self.current
        self.current += 1
        return current
        
# Створюємо екземпляр користувацького ітератора
my_iter = MyIterator(1, 5)
        
# Використовуємо ітератор для перегляду елементів
for num in my_iter:
    print(num)

5.3 Правильний ітератор

Чим поганий ітератор з попереднього прикладу? Так, це ітератор, він робочий, але він занадто примітивний. З його допомогою не можна йти по одній і тій же колекції елементів одночасно різними ітераторами.

Більш правильно було б написати код, який повертав не посилання на себе в методі __iter__, а окремий об'єкт, який би вже правильно повертав усі елементи.

Приклад:


class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        return MyIterator(self.data)
    
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item
    
# Використання
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
    print(item)
    

У цьому прикладі у нас є два класи — у перший передається колекція, по якій ми будемо йти ітератором. А другий — це і є ітератор, який повертає елементи колекції в методі next(). Він також доволі простий, але саме так потрібно додавати ітератори в твої класи.

1
Опитування
Модулі та пакети, рівень 11, лекція 4
Недоступний
Модулі та пакети
Модулі та пакети
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ