Iteratory Pythona (__iter__ i __next__): jak go używać i dlaczego?

Iteratory to obiekty, na których można dokonywać iteracji. W tym samouczku dowiesz się, jak działa iterator i jak zbudować swój własny iterator przy użyciu metod __iter__ i __next__.

Wideo: Iteratory Pythona

Iteratory w Pythonie

Iteratory są wszędzie w Pythonie. Są elegancko zaimplementowane w forpętlach, zrozumieniach, generatorach itp., Ale są ukryte na widoku.

Iterator w Pythonie to po prostu obiekt, po którym można iterować. Obiekt, który zwróci dane, jeden element na raz.

Technicznie rzecz biorąc, Python iterator obiekt musi implementować dwie metody specjalne, __iter__()a __next__()zbiorczo nazywane protokół iterator .

Obiekt nazywany jest iterowalnym, jeśli możemy uzyskać z niego iterator. Większość kontenerów wbudowanych w Pythonie, takich jak: lista, krotka, łańcuch znaków itp., Jest iterowalna.

iter()Funkcja (który z kolei wywołuje __iter__()metodę) zwraca iterator od nich.

Iteracja przez Iterator

Używamy tej next()funkcji do ręcznego iteracji przez wszystkie elementy iteratora. Kiedy dojdziemy do końca i nie ma już danych do zwrócenia, podniesie to StopIterationwyjątek. Oto przykład.

 # 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)

Wynik

 4 7 0 3 Traceback (ostatnie ostatnie połączenie): Plik „”, wiersz 24, w następnym (my_iter) StopIteration

Bardziej eleganckim sposobem automatycznej iteracji jest użycie pętli for. Używając tego, możemy iterować po każdym obiekcie, który może zwrócić iterator, na przykład listę, ciąg, plik itp.

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

Działanie pętli for dla iteratorów

Jak widać w powyższym przykładzie, forpętla była w stanie automatycznie iterować po liście.

W rzeczywistości forpętla może iterować po każdej iterowalnej. Przyjrzyjmy się bliżej, jak forpętla jest faktycznie zaimplementowana w Pythonie.

 for element in iterable: # do something with element

Jest faktycznie zaimplementowany jako.

 # 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

Zatem wewnętrznie forpętla tworzy obiekt iteratora, iter_objwywołując iter()iterowalny.

Jak na ironię, ta forpętla jest w rzeczywistości nieskończoną pętlą while.

Wewnątrz pętli wywołuje next()pobranie następnego elementu i wykonuje treść forpętli z tą wartością. Po wyczerpaniu wszystkich przedmiotów StopIterationpodnosi się, co jest wewnętrznie chwytane i pętla się kończy. Zauważ, że każdy inny rodzaj wyjątku przejdzie.

Tworzenie niestandardowych iteratorów

Budowanie iteratora od podstaw jest łatwe w Pythonie. Musimy tylko wdrożyć __iter__(), a __next__()metod.

__iter__()Sposób wraca do iteracyjnej samego obiektu. W razie potrzeby można przeprowadzić inicjalizację.

__next__()Metoda musi zwrócić następny element w sekwencji. Po dojściu do końca iw kolejnych sprawdzeniach musi podbić StopIteration.

Tutaj pokazujemy przykład, który da nam następną potęgę 2 w każdej iteracji. Wykładnik potęgi zaczyna się od zera do wartości zestawu użytkownika.

Jeśli nie masz pojęcia o programowaniu obiektowym, odwiedź Python Object-Oriented Programming.

 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))

Wynik

 1 2 4 8 Traceback (ostatnie połączenie ostatnio): File "/home/bsoyuj/Desktop/Untitled-1.py", wiersz 32, w druku (next (i)) Plik "", wiersz 18, w __next__ podnieś StopIteration Zatrzymanie

Możemy również użyć forpętli do iteracji po naszej klasie iteratora.

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

Nieskończone Iteratory Pythona

Nie jest konieczne, aby element w obiekcie iteratora musiał zostać wyczerpany. Mogą istnieć nieskończone iteratory (które nigdy się nie kończą). Podczas obsługi takich iteratorów musimy zachować ostrożność.

Oto prosty przykład pokazujący nieskończone iteratory.

Funkcja iter()funkcji wbudowanej może być wywołana z dwoma argumentami, przy czym pierwszy argument musi być wywoływalnym obiektem (funkcją), a drugi to wartownik. Iterator wywołuje tę funkcję, aż zwrócona wartość będzie równa wartownikowi.

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

Widzimy, że int()funkcja zawsze zwraca 0. Zatem przekazanie jej jako iter(int,1)zwróci iterator, który wywołuje int()aż zwrócona wartość będzie równa 1. To się nigdy nie zdarza i otrzymujemy nieskończony iterator.

Możemy również zbudować własne nieskończone iteratory. Poniższy iterator teoretycznie zwróci wszystkie liczby nieparzyste.

 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

Przykładowy przebieg wyglądałby następująco.

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

I tak dalej…

Podczas iteracji po tego typu nieskończonych iteratorach należy uważać, aby dołączyć warunek kończący.

Zaletą używania iteratorów jest oszczędność zasobów. Jak pokazano powyżej, mogliśmy uzyskać wszystkie liczby nieparzyste bez przechowywania całego systemu liczbowego w pamięci. W skończonej pamięci możemy mieć nieskończone przedmioty (teoretycznie).

Istnieje łatwiejszy sposób tworzenia iteratorów w Pythonie. Aby dowiedzieć się więcej, odwiedź: Generatory Pythona używające yield.

Interesujące artykuły...