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()
. Він також доволі простий, але саме так потрібно додавати ітератори в твої класи.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ