Python-iterators (__iter__ en __next__): hoe te gebruiken en waarom?

Iteratoren zijn objecten waarop kan worden herhaald. In deze tutorial leer je hoe iterator werkt en hoe je je eigen iterator kunt bouwen met de __iter__ en __next__ methoden.

Video: Python-iteratoren

Iterators in Python

Iterators zijn overal in Python. Ze zijn elegant geïmplementeerd in forlussen, begrip, generatoren enz. Maar zijn in het volle zicht verborgen.

Iterator in Python is gewoon een object dat kan worden herhaald. Een object dat gegevens retourneert, één element tegelijk.

Technisch gezien een Python iteratorobject moeten twee bijzondere manieren implementeren, __iter__()en __next__(), samen het iterator protocol .

Een object wordt iterabel genoemd als we er een iterator uit kunnen halen. De meeste ingebouwde containers in Python zoals: list, tuple, string etc. zijn iterables.

De iter()functie (die op zijn beurt de __iter__()methode aanroept) retourneert een iterator van hen.

Itereren door een iterator

We gebruiken de next()functie om handmatig alle items van een iterator te doorlopen. Wanneer we het einde bereiken en er zijn geen gegevens meer om te retourneren, zal dit de StopIterationuitzondering verhogen . Hieronder volgt een voorbeeld.

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

Uitvoer

 4 7 0 3 Traceback (laatste oproep laatste): Bestand "", regel 24, in volgende (my_iter) StopIteration

Een elegantere manier om automatisch te herhalen, is door de for-lus te gebruiken. Hiermee kunnen we elk object herhalen dat een iterator kan retourneren, bijvoorbeeld lijst, tekenreeks, bestand enz.

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

Werken van for loop voor iterators

Zoals we in het bovenstaande voorbeeld zien, kon de forlus automatisch door de lijst herhalen.

In feite kan de forlus elke iterabele herhalen. Laten we eens nader bekijken hoe de forlus feitelijk in Python is geïmplementeerd.

 for element in iterable: # do something with element

Is eigenlijk geïmplementeerd als.

 # 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

Dus intern forcreëert de lus een iteratorobject iter_objdoor iter()de iterable aan te roepen.

Ironisch genoeg is deze forlus eigenlijk een oneindige while-lus.

Binnen de lus roept het next()op om het volgende element op te halen en voert het de body van de forlus uit met deze waarde. Nadat alle items zijn uitgeput, StopIterationwordt deze intern opgevangen en eindigt de lus. Merk op dat elke andere vorm van uitzondering zal passeren.

Aangepaste iteratoren bouwen

Het bouwen van een iterator vanaf het begin is eenvoudig in Python. We hoeven alleen de __iter__()en de __next__()methoden te implementeren .

De __iter__()methode retourneert het iterator-object zelf. Indien nodig kan enige initialisatie worden uitgevoerd.

De __next__()methode moet het volgende item in de reeks retourneren. Bij het bereiken van het einde, en in daaropvolgende oproepen, moet het verhogen StopIteration.

Hier laten we een voorbeeld zien dat ons de volgende macht van 2 geeft in elke iteratie. Machtsexponent begint vanaf nul tot een door de gebruiker ingesteld nummer.

Als je geen idee hebt van objectgeoriënteerd programmeren, ga dan naar 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))

Uitvoer

 1 2 4 8 Traceback (meest recente oproep laatste): File "/home/bsoyuj/Desktop/Untitled-1.py", regel 32, in print (volgende (i)) Bestand "", regel 18, in __next__ verhoog StopIteration StopIteratie

We kunnen ook een forlus gebruiken om onze iteratorklasse te herhalen.

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

Python Infinite Iterators

Het is niet nodig dat het item in een iteratorobject uitgeput hoeft te zijn. Er kunnen oneindige iteratoren zijn (die nooit eindigen). We moeten voorzichtig zijn bij het omgaan met dergelijke iteratoren.

Hier is een eenvoudig voorbeeld om oneindige iteratoren te demonstreren.

De ingebouwde functie- iter()functie kan worden aangeroepen met twee argumenten waarbij het eerste argument een oproepbaar object (functie) moet zijn en het tweede de schildwacht. De iterator roept deze functie aan totdat de geretourneerde waarde gelijk is aan de sentinel.

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

We kunnen zien dat de int()functie altijd 0 retourneert. Dus als je het zo iter(int,1)doorgeeft, wordt er een iterator int()geretourneerd die aanroept totdat de geretourneerde waarde gelijk is aan 1. Dit gebeurt nooit en we krijgen een oneindige iterator.

We kunnen ook onze eigen oneindige iteratoren bouwen. De volgende iterator retourneert theoretisch alle oneven getallen.

 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

Een voorbeeldrun zou als volgt zijn.

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

Enzovoort…

Zorg ervoor dat u een afsluitende voorwaarde opneemt bij het herhalen van dit soort oneindige iteratoren.

Het voordeel van het gebruik van iteratoren is dat ze bronnen besparen. Zoals hierboven getoond, kunnen we alle oneven nummers krijgen zonder het hele nummerstelsel in het geheugen op te slaan. We kunnen (theoretisch) oneindige items in het eindige geheugen hebben.

Er is een eenvoudigere manier om iterators in Python te maken. Ga voor meer informatie naar: Python-generatoren die opbrengst gebruiken.

Interessante artikelen...