Sari la conținutul principal

Tutorial despre Iteratori și Generatoare în Python

Explorează diferența dintre iteratorii și generatoarele din Python și află care sunt cele mai potrivite de folosit în diverse situații.
Actualizat 25 mai 2026  · 10 min. citire

Iteratorii sunt obiecte peste care se poate itera. Ei reprezintă o funcționalitate comună a limbajului de programare Python, folosită discret pentru bucle și list comprehensions. Orice obiect care poate furniza un iterator este cunoscut drept un iterabil. 

Construirea unui iterator implică destul de multă muncă. De exemplu, implementarea fiecărui obiect iterator trebuie să conțină metodele __iter__() și __next__() . Pe lângă cerința de mai sus, implementarea trebuie să aibă și un mod de a urmări starea internă a obiectului și de a ridica o excepție StopIteration odată ce nu mai pot fi returnate valori. Aceste reguli sunt cunoscute drept protocolul iteratorului

Implementarea propriului tău iterator este un proces anevoios și nu este întotdeauna necesară. O alternativă mai simplă este folosirea unui generator. Generatoarele sunt un tip special de funcție care folosesc cuvântul-cheie yield pentru a returna un iterator peste care se poate itera, câte o valoare pe rând. 

Abilitatea de a distinge situațiile potrivite pentru a implementa un iterator sau pentru a folosi un generator îți va îmbunătăți abilitățile de programator Python. În restul acestui tutorial, vom sublinia diferențele dintre cele două obiecte, ca să te ajutăm să decizi care este cel mai potrivit în diverse situații. 

Glosar

Termen

Definiție

Iterabil 

Un obiect Python care poate fi parcurs într-o buclă. Exemple de iterabile includ liste, seturi, tuple, dicționare, șiruri de caractere etc. 

Iterator

Un iterator este un obiect peste care se poate itera. Prin urmare, iteratorii conțin un număr numărabil de valori. 

Generator

Un tip special de funcție care nu returnează o singură valoare: returnează un obiect iterator cu o secvență de valori.

Evaluare leneșă (Lazy Evaluation) 

O strategie de evaluare prin care anumite obiecte sunt produse doar atunci când sunt necesare. În consecință, în anumite cercuri de dezvoltatori, evaluarea leneșă mai este numită și „call-by-need”.

Protocolul iteratorului 

Un set de reguli care trebuie urmate pentru a defini un iterator în Python. 

next()

O funcție built-in folosită pentru a returna elementul următor dintr-un iterator. 

iter()

O funcție built-in folosită pentru a converti un iterabil într-un iterator. 

yield()

Un cuvânt-cheie Python similar cu return, cu diferența că yield returnează un obiect generator în loc de o valoare. 

Iteratori și iterabile în Python

Iterabilele sunt obiecte capabile să-și returneze elementele pe rând – pot fi parcurse. Structuri de date Python populare built-in precum listele, tuplele și seturile se califică drept iterabile. Alte structuri de date precum șirurile și dicționarele sunt, de asemenea, considerate iterabile: un șir poate fi parcurs prin caracterele sale, iar cheile unui dicționar pot fi parcurse. Ca regulă generală, consideră iterabil orice obiect care poate fi parcurs într-o buclă for. 

Explorarea iterabilelor Python cu exemple

Având aceste definiții, putem concluziona că toți iteratorii sunt, de asemenea, iterabile. Totuși, nu orice iterabil este neapărat și iterator. Un iterabil produce un iterator doar când este parcurs.

Pentru a demonstra această funcționalitate, vom instanția o listă, care este un iterabil, și vom produce un iterator apelând funcția built-in iter() pe listă. 

list_instance = [1, 2, 3, 4]
print(iter(list_instance))

"""
<list_iterator object at 0x7fd946309e90>
"""

Deși lista în sine nu este un iterator, apelarea funcției iter() o convertește într-un iterator și returnează obiectul iterator.

Ca să demonstrăm că nu toate iterabilele sunt și iteratori, vom instanția aceeași listă și vom încerca să apelăm funcția next(), care este folosită pentru a returna următorul element dintr-un iterator.  

list_instance = [1, 2, 3, 4]
print(next(list_instance))
"""
--------------------------------------------------------------------
TypeError                         Traceback (most recent call last)
<ipython-input-2-0cb076ed2d65> in <module>()
    3 print(iter(list_instance))
    4
----> 5 print(next(list_instance))
TypeError: 'list' object is not an iterator
"""

În codul de mai sus, poți vedea că încercarea de a apela funcția next() pe listă a ridicat un TypeError – află mai multe despre gestionarea excepțiilor și erorilor în Python. Acest comportament a apărut din simplul motiv că o listă este un iterabil și nu un iterator. 

Explorarea iteratorilor Python cu exemple

Așadar, dacă scopul este să parcurgi o listă, atunci mai întâi trebuie produs un obiect iterator. Abia apoi putem gestiona parcurgerea valorilor listei.

# instantiate a list object
list_instance = [1, 2, 3, 4]

# convert the list to an iterator
iterator = iter(list_instance)

# return items one at a time
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
"""
1
2
3
4
"""

Python produce automat un obiect iterator ori de câte ori încerci să parcurgi un obiect iterabil. 

# instantiate a list object
list_instance = [1, 2, 3, 4]

# loop through the list
for item in list_instance:
  print(item)
"""
1
2
3
4
"""

Când excepția StopIteration este prinsă, bucla se încheie.

Valorile obținute dintr-un iterator pot fi preluate doar de la stânga la dreapta. Python nu are o funcție previous() care să le permită dezvoltatorilor să meargă înapoi printr-un iterator. 

Natura „leneșă” a iteratorilor

Este posibil să definești mai mulți iteratori bazați pe același obiect iterabil. Fiecare iterator își va menține propria stare de progres. Astfel, definind mai multe instanțe de iterator ale unui obiect iterabil, este posibil să parcurgi până la capăt o instanță, în timp ce cealaltă rămâne la început.

list_instance = [1, 2, 3, 4]
iterator_a = iter(list_instance)
iterator_b = iter(list_instance)
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"B: {next(iterator_b)}")
"""
A: 1
A: 2
A: 3
A: 4
B: 1
"""

Observă că iterator_b afișează primul element al seriei.

Astfel, putem spune că iteratorii au o natură leneșă: când este creat un iterator, elementele nu sunt livrate până când nu sunt cerute. Cu alte cuvinte, elementele listei noastre ar fi returnate doar atunci când le cerem explicit cu next(iter(list_instance))

Totuși, toate valorile dintr-un iterator pot fi extrase dintr-o dată apelând un container iterabil built-in (adică, list(), set(), tuple()) pe obiectul iterator, forțându-l să-și genereze toate elementele deodată.

# instantiate iterable
list_instance = [1, 2, 3, 4]

# produce an iterator from an iterable
iterator = iter(list_instance)
print(list(iterator))
"""
[1, 2, 3, 4]
"""

Acest lucru nu este recomandat pentru iteratori mari, deoarece obligă generarea tuturor elementelor și păstrarea lor în memorie simultan, ceea ce anulează scopul evaluării leneșe.

Când un set de date este prea mare pentru a încăpea confortabil în memorie sau când vrei o parcurgere „leneșă” fără a scrie o clasă completă de iterator, de obicei un generator este o alegere mai bună.

Generatoare în Python

Cea mai rapidă alternativă la implementarea unui iterator este folosirea unui generator. Deși generatoarele pot arăta ca niște funcții Python obișnuite, ele sunt diferite. Pentru început, un generator nu returnează elemente în mod obișnuit. În schimb, folosește cuvântul-cheie yield pentru a genera elemente din mers. Astfel, putem spune că un generator este un tip special de funcție care valorifică evaluarea leneșă.

Generatoarele nu își stochează conținutul în memorie așa cum te-ai aștepta de la un iterabil obișnuit. De exemplu, dacă scopul ar fi să găsim toți divizorii unui număr întreg pozitiv, în mod tipic am implementa o funcție tradițională (află mai multe despre funcțiile Python în acest tutorial) astfel:  

def factors(n):
  factor_list = []
  for val in range(1, n+1):
      if n % val == 0:
          factor_list.append(val)
  return factor_list

print(factors(20))
"""
[1, 2, 4, 5, 10, 20]
"""

Codul de mai sus returnează întreaga listă de divizori. Totuși, observă diferența când este folosit un generator în locul unei funcții Python tradiționale:

def factors(n):
  for val in range(1, n+1):
      if n % val == 0:
          yield val
print(factors(20))

"""
<generator object factors at 0x7fd938271350>
"""

Deoarece am folosit cuvântul-cheie yield în loc de return, funcția nu iese după rulare. În esență, i-am spus lui Python să creeze un obiect generator în loc de o funcție tradițională, ceea ce permite urmărirea stării generatorului. 

În consecință, este posibil să apelăm funcția next() pe iteratorul „leneș” pentru a afișa elementele seriei pe rând. 

def factors(n):
  for val in range(1, n+1):
      if n % val == 0:
          yield val
         
factors_of_20 = factors(20)
print(next(factors_of_20))

"""
1
"""

O altă modalitate de a crea un generator este printr-o comprehensiune de generator. Expresiile generator adoptă o sintaxă similară cu a list comprehension-urilor, cu diferența că folosesc paranteze rotunde în loc de pătrate.

factor_gen = (val for val in range(1, 21) if 20 % val == 0)
print(list(factor_gen))
"""
[1, 2, 4, 5, 10, 20]
"""

Explorarea cuvântului-cheie yield în Python

Cuvântul-cheie yield controlează fluxul unei funcții generator. În loc să iasă din funcție, cum se întâmplă când este folosit return, cuvântul-cheie yield întoarce din funcție, dar reține starea variabilelor locale.

Generatorul returnat din apelul yield poate fi atribuit unei variabile și parcurs cu funcția next() – aceasta va executa funcția până la primul cuvânt-cheie yield întâlnit. Odată ce a fost atins yield, execuția funcției este suspendată. Când se întâmplă asta, starea funcției este salvată. Astfel, putem relua execuția funcției când dorim. 

Funcția va continua de la apelul către yield. De exemplu: 

def yield_multiple_statements():
  yield "This is the first statement"
  yield "This is the second statement"  
  yield "This is the third statement"
  yield "This is the last statement. Don't call next again!"
example = yield_multiple_statements()
print(next(example))
print(next(example))
print(next(example))
print(next(example))
print(next(example))
"""
This is the first statement
This is the second statement
This is the third statement
This is the last statement. Don't call next again or else!
--------------------------------------------------------------------
StopIteration                  Traceback (most recent call last)
<ipython-input-25-4aaf9c871f91> in <module>()
    11 print(next(example))
    12 print(next(example))
---> 13 print(next(example))
StopIteration:
"""

În codul de mai sus, generatorul nostru are patru apeluri yield, dar încercăm să apelăm next pe el de cinci ori, ceea ce a ridicat o excepție StopIteration. Acest comportament a apărut deoarece generatorul nostru nu este o serie infinită, așa că apelarea lui de mai multe ori decât este de așteptat a epuizat generatorul.

Concluzie 

Pe scurt, iteratorii sunt obiecte peste care se poate itera, iar generatoarele sunt funcții speciale care valorifică evaluarea leneșă. Implementarea propriului tău iterator înseamnă că trebuie să creezi metodele __iter__() și __next__(), în timp ce un generator poate fi implementat folosind cuvântul-cheie yield într-o funcție sau într-o comprehensiune Python. 

Poți prefera un iterator personalizat în locul unui generator atunci când ai nevoie de un obiect cu un comportament complex de menținere a stării sau dacă vrei să expui și alte metode în afară de __next__(), __iter__() și __init__(). Pe de altă parte, un generator poate fi preferabil când lucrezi cu seturi mari de date, deoarece nu își stochează conținutul în memorie, sau când nu este necesar să implementezi un iterator. 

FAQ-uri

Care este diferența dintre un iterator și un generator în Python?

Un iterator este orice obiect care implementează __iter__() și __next__(). Un generator este o modalitate mai simplă de a crea un iterator folosind o funcție cu cuvântul-cheie yield. Toate generatoarele sunt iteratori, dar nu toți iteratorii sunt generatoare.

Când ar trebui să folosesc un generator în locul unei liste în Python?

Folosește un generator pentru secvențe mari sau infinite, ori atunci când contează eficiența memoriei. Listele păstrează toate elementele în memorie deodată, în timp ce generatoarele produc câte o valoare pe rând. Pentru seturi mici de date pe care le vei reutiliza, de obicei o listă este în regulă.

Ce face cuvântul-cheie yield în Python?

Cuvântul-cheie yield transformă o funcție într-un generator. În loc să returneze și să iasă, yield pune funcția pe pauză, returnează o valoare și își amintește starea astfel încât execuția să poată continua la următorul apel.

Cum creezi un generator în Python?

Fie scrii o funcție care folosește yield în loc de return, fie folosești o expresie generator — aceeași sintaxă ca la un list comprehension, dar cu paranteze rotunde, de tipul (x * 2 for x in range(10)).

Generatoarele sunt mai rapide decât iteratorii în Python?

Nu ca viteză brută, dar sunt mai eficiente din punct de vedere al memoriei deoarece produc valori la cerere. Pentru seturi mari de date asta înseamnă adesea performanță generală mai bună; pentru cele mici, diferența este neglijabilă.

Subiecte

Cursuri Python de top

course

Intermediate Python

4 oră
1.4M
Level up your data science skills by creating visualizations using Matplotlib and manipulating DataFrames with pandas.
Vezi detaliiRight Arrow
Începeți cursul
Vezi mai multRight Arrow