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 for
pę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 StopIteration
wyją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, for
pętla była w stanie automatycznie iterować po liście.
W rzeczywistości for
pętla może iterować po każdej iterowalnej. Przyjrzyjmy się bliżej, jak for
pę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 for
pętla tworzy obiekt iteratora, iter_obj
wywołując iter()
iterowalny.
Jak na ironię, ta for
pętla jest w rzeczywistości nieskończoną pętlą while.
Wewnątrz pętli wywołuje next()
pobranie następnego elementu i wykonuje treść for
pętli z tą wartością. Po wyczerpaniu wszystkich przedmiotów StopIteration
podnosi 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ć for
pę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.