Python итератори (__iter__ и __next__): Как да го използвам и защо?

Итераторите са обекти, които могат да бъдат повторени. В този урок ще научите как работи итераторът и как можете да изградите свой собствен итератор, използвайки методите __iter__ и __next__.

Видео: Python Iterators

Итератори в Python

Итераторите са навсякъде в Python. Те са елегантно изпълнени в forцикли, схващания, генератори и т.н., но са скрити на видно място.

Итераторът в Python е просто обект, който може да бъде повторен. Обект, който ще връща данни, един по един елемент.

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

Обектът се нарича итерируем, ако можем да получим итератор от него. Повечето вградени контейнери в 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всъщност се изпълнява цикълът в 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.

Интересни статии...