Ітератори Python (__iter__ та __next__): як ним користуватися та чому?

Ітератори - це об’єкти, які можна повторити. У цьому підручнику ви дізнаєтесь, як працює ітератор та як ви можете створити власний ітератор, використовуючи методи __iter__ та __next__.

Відео: Ітератори Python

Ітератори в Python

Ітератори є всюди в Python. Вони елегантно реалізовані в forциклах, розуміннях, генераторах тощо, але приховані на виду.

Ітератор у Python - це просто об’єкт, який можна повторити. Об'єкт, який поверне дані, по одному елементу.

Технічно кажучи, об'єкт ітератора Python повинен реалізовувати два спеціальні методи __iter__()і __next__()спільно називатися протоколом ітератора .

Об’єкт називається iterable, якщо ми можемо отримати від нього ітератор. Більшість вбудованих контейнерів на Python, таких як: список, кортеж, рядок тощо, є ітерабельними.

iter()Функція (яка , в свою чергу , викликає __iter__()метод) повертає ітератор з них.

Ітерація через ітератор

Ми використовуємо next()функцію для ітерації вручну всіх елементів ітератора. Коли ми дійдемо до кінця і більше не буде повернених даних, це призведе до StopIterationвинятку. Ось приклад.

 # define a list my_list = (4, 7, 0, 3) # get an iterator using iter() my_iter = iter(my_list) # iterate through it using next() # Output: 4 print(next(my_iter)) # Output: 7 print(next(my_iter)) # next(obj) is same as obj.__next__() # Output: 0 print(my_iter.__next__()) # Output: 3 print(my_iter.__next__()) # This will raise error, no items left next(my_iter)

Вихідні дані

 4 7 0 3 Traceback (останній дзвінок останній): Файл "", рядок 24, у наступному (my_iter) StopIteration

Більш елегантний спосіб автоматичної ітерації - використання циклу for. Використовуючи це, ми можемо перебирати будь-який об’єкт, який може повернути ітератор, наприклад список, рядок, файл тощо.

 >>> for element in my_list:… print(element)… 4 7 0 3

Робота циклу for для ітераторів

Як ми бачимо у наведеному вище прикладі, forцикл зміг автоматично перебирати список.

Насправді forцикл може перебирати будь-який ітерабель. Давайте детальніше розглянемо, як forнасправді реалізується цикл у Python.

 for element in iterable: # do something with element

Реально реалізовано як.

 # create an iterator object from that iterable iter_obj = iter(iterable) # infinite loop while True: try: # get the next item element = next(iter_obj) # do something with element except StopIteration: # if StopIteration is raised, break from loop break

Отже, внутрішньо forцикл створює ітератор, iter_objвикликаючи iter()ітерабель.

Як не дивно, але цей forцикл насправді є нескінченним циклом while.

Усередині циклу він закликає next()отримати наступний елемент і виконує тіло forциклу з цим значенням. Після того, як всі предмети вихлопуються, StopIterationпіднімається, який внутрішньо затримується і петля закінчується. Зверніть увагу, що будь-який інший виняток буде пройдений.

Створення користувацьких ітераторів

Створити ітератор з нуля в Python легко. Ми просто повинні реалізувати __iter__()і на __next__()методи.

__iter__()Метод повертає сам об'єкт ітератора. Якщо потрібно, можна виконати певну ініціалізацію.

__next__()Метод повинен повертати наступний елемент в послідовності. Після досягнення кінця та наступних дзвінків він повинен піднятися StopIteration.

Тут ми покажемо приклад, який дасть нам наступну ступінь 2 у кожній ітерації. Показник потужності починається від нуля до числа, встановленого користувачем.

Якщо у вас немає уявлення про об’єктно-орієнтоване програмування, відвідайте об’єктно-орієнтоване програмування Python.

 class PowTwo: """Class to implement an iterator of powers of two""" def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # create an object numbers = PowTwo(3) # create an iterable from the object i = iter(numbers) # Using next to get to the next iterator element print(next(i)) print(next(i)) print(next(i)) print(next(i)) print(next(i))

Вихідні дані

 1 2 4 8 Traceback (останній дзвінок останній): Файл "/home/bsoyuj/Desktop/Untitled-1.py", рядок 32, у друці (наступний (i)) Файл "", рядок 18, у __next__ підняти StopIteration StopIteration

Ми також можемо використовувати forцикл для перебору нашого класу ітераторів.

 >>> for i in PowTwo(5):… print(i)… 1 2 4 8 16 32

Нескінченні ітератори Python

Не обов'язково, що елемент в об'єкті ітератора повинен бути вичерпаний. Можуть бути нескінченні ітератори (які ніколи не закінчуються). Ми повинні бути обережними при роботі з такими ітераторами.

Ось простий приклад для демонстрації нескінченних ітераторів.

The built-in function iter() function can be called with two arguments where the first argument must be a callable object (function) and second is the sentinel. The iterator calls this function until the returned value is equal to the sentinel.

 >>> int() 0 >>> inf = iter(int,1) >>> next(inf) 0 >>> next(inf) 0

We can see that the int() function always returns 0. So passing it as iter(int,1) will return an iterator that calls int() until the returned value equals 1. This never happens and we get an infinite iterator.

We can also build our own infinite iterators. The following iterator will, theoretically, return all the odd numbers.

 class InfIter: """Infinite iterator to return all odd numbers""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num

A sample run would be as follows.

 >>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7

And so on…

Be careful to include a terminating condition, when iterating over these types of infinite iterators.

Перевага використання ітераторів полягає в тому, що вони економлять ресурси. Як показано вище, ми могли отримати всі непарні числа, не зберігаючи всю систему числення в пам'яті. Ми можемо мати нескінченні елементи (теоретично) в кінцевій пам’яті.

Існує простіший спосіб створити ітератори в Python. Щоб дізнатись більше, відвідайте: Генератори Python з використанням yield.

Цікаві статті...