Python Iterators (__iter__ și __next__): Cum se folosește și de ce?

Iteratorii sunt obiecte care pot fi repetate. În acest tutorial, veți afla cum funcționează iteratorul și cum vă puteți construi propriul iterator folosind metodele __iter__ și __urmatoarele__.

Video: Iteratori Python

Iteratori în Python

Iteratorii sunt peste tot în Python. Acestea sunt implementate elegant în forbucle, înțelegeri, generatoare etc., dar sunt ascunse la vedere.

Iteratorul din Python este pur și simplu un obiect care poate fi iterat. Un obiect care va returna date, câte un element pe rând.

Din punct de vedere tehnic, un obiect iterator Python trebuie să implementeze două metode speciale __iter__()și __next__(), denumit colectiv protocolul iterator .

Un obiect este numit iterabil dacă putem obține un iterator din acesta. Cele mai multe containere încorporate din Python, cum ar fi: listă, tuplu, șir etc., sunt iterabile.

iter()Funcția (care , la rândul său , apelează __iter__()metoda) returneaza un iterator de la ei.

Iterând printr-un iterator

Folosim next()funcția pentru a itera manual toate elementele unui iterator. Când ajungem la final și nu mai sunt date de returnat, va ridica StopIterationExcepția. Următorul este un exemplu.

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

Ieșire

 4 7 0 3 Traceback (ultimul apel cel mai recent): Fișierul "", linia 24, în următorul (my_iter) StopIteration

O modalitate mai elegantă de a itera automat este folosirea buclei for. Folosind aceasta, putem itera peste orice obiect care poate returna un iterator, de exemplu listă, șir, fișier etc.

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

Funcționarea buclei for pentru iteratoare

După cum vedem în exemplul de mai sus, forbucla a reușit să itereze automat prin listă.

De fapt, forbucla poate itera peste orice iterabil. Să aruncăm o privire mai atentă asupra modului în care forbucla este de fapt implementată în Python.

 for element in iterable: # do something with element

Este de fapt implementat ca.

 # 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

Deci intern, forbucla creează un obiect iterator, iter_objapelând iter()la iterabil.

În mod ironic, această forbuclă este de fapt o buclă while infinită.

În interiorul buclei, apelează next()pentru a obține următorul element și execută corpul forbuclei cu această valoare. După toate obiectele de evacuare, StopIterationeste ridicat care este prins intern și bucla se termină. Rețineți că orice alt tip de excepție va trece.

Construirea de iteratoare personalizate

Construirea unui iterator de la zero este ușoară în Python. Trebuie doar să implementăm __iter__()și __next__()metodele.

__iter__()Metoda returnează obiectul iterator în sine. Dacă este necesar, se poate efectua o anumită inițializare.

__next__()Metoda trebuie să returneze elementul următor din secvență. La atingerea finalului și în apelurile ulterioare, acesta trebuie să crească StopIteration.

Aici, vă prezentăm un exemplu care ne va oferi următoarea putere de 2 în fiecare iterație. Exponentul de putere începe de la zero până la un număr stabilit de utilizator.

Dacă nu aveți nicio idee despre programarea orientată pe obiecte, vizitați Programarea orientată pe obiecte 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))

Ieșire

 1 2 4 8 Traceback (ultimul apel cel mai recent): Fișierul "/home/bsoyuj/Desktop/Untitled-1.py", linia 32, în tipar (următorul (i)) Fișierul "", linia 18, în __următorul__ ridicați StopIteration StopIteration

De asemenea, putem folosi o forbuclă pentru a itera peste clasa noastră de iteratori.

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

Python Infinite Iterators

Nu este necesar ca elementul dintr-un obiect iterator să fie epuizat. Pot exista iteratori infiniti (care nu se termină niciodată). Trebuie să fim atenți atunci când manipulăm astfel de iteratori.

Iată un exemplu simplu pentru a demonstra iteratori infiniti.

Funcția de funcție iter()încorporată poate fi apelată cu două argumente în care primul argument trebuie să fie un obiect apelabil (funcție) și al doilea este santinela. Iteratorul apelează această funcție până când valoarea returnată este egală cu sentinela.

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

Putem vedea că int()funcția întotdeauna returnează 0. Deci, trecând-o ca se iter(int,1)va returna un iterator care apelează int()până când valoarea returnată este egală cu 1. Acest lucru nu se întâmplă niciodată și obținem un iterator infinit.

De asemenea, ne putem construi proprii iteratori infiniti. Următorul iterator va returna teoretic toate numerele impare.

 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

O probă de execuție ar fi următoarea.

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

Și așa mai departe…

Aveți grijă să includeți o condiție de terminare, atunci când iterați asupra acestor tipuri de iteratori infiniti.

Avantajul utilizării iteratorilor este că economisesc resurse. Așa cum se arată mai sus, am putea obține toate numerele impare fără a stoca întregul sistem numeric în memorie. Putem avea elemente infinite (teoretic) în memoria finită.

Există o modalitate mai ușoară de a crea iteratori în Python. Pentru a afla mai multe, vizitați: Generatoare Python folosind randament.

Articole interesante...