Thanks to visit codestin.com
Credit goes to www.datacamp.com

Przejdź do treści głównej

Samouczek: Iteratory i generatory w Pythonie

Poznaj różnicę między iteratorami i generatorami w Pythonie oraz dowiedz się, które najlepiej sprawdzają się w różnych sytuacjach.
Zaktualizowano 25 maj 2026  · 10 min Czytać

Iteratory to obiekty, po których można iterować. To powszechna funkcja języka Python, wygodnie wykorzystywana w pętlach i składni list comprehensions. Każdy obiekt, który potrafi utworzyć iterator, nazywamy iterowalnym (iterable). 

Stworzenie iteratora wymaga sporo pracy. Na przykład implementacja każdego obiektu iteratora musi zawierać metody __iter__() i __next__() . Oprócz tego implementacja musi śledzić stan wewnętrzny obiektu i zgłaszać wyjątek StopIteration, gdy nie można już zwrócić kolejnych wartości. Te zasady określa protokół iteratora

Implementowanie własnego iteratora jest czasochłonne i nie zawsze konieczne. Prostszą alternatywą jest użycie generatora. Generatory to szczególny rodzaj funkcji, które używają słowa kluczowego yield, aby zwrócić iterator, po którym można iterować — po jednej wartości na raz. 

Umiejętność rozpoznania, kiedy zaimplementować iterator, a kiedy użyć generatora, poprawi twoje kompetencje jako programisty Pythona. W dalszej części tego samouczka podkreślimy różnice między tymi dwoma obiektami, co pomoże ci wybrać najlepsze rozwiązanie w różnych sytuacjach. 

Glosariusz

Termin

Definicja

Iterable 

Obiekt Pythona, po którym można wykonać iterację w pętli. Przykładami iterowalnych struktur są listy, zbiory, krotki, słowniki, łańcuchy znaków itd. 

Iterator

Iterator to obiekt, po którym można iterować. Zawiera więc przeliczalną liczbę wartości. 

Generator

Szczególny rodzaj funkcji, która nie zwraca pojedynczej wartości, lecz obiekt iteratora z sekwencją wartości.

Leniwa ewaluacja 

Strategia obliczeń, w której pewne obiekty są tworzone dopiero wtedy, gdy są potrzebne. Dlatego w niektórych kręgach deweloperskich leniwa ewaluacja bywa nazywana „call-by-need”.

Protokół iteratora 

Zbiór zasad, których należy przestrzegać, aby zdefiniować iterator w Pythonie. 

next()

Funkcja wbudowana służąca do zwracania następnego elementu iteratora. 

iter()

Funkcja wbudowana służąca do przekształcenia obiektu iterowalnego w iterator. 

yield()

Słowo kluczowe w Pythonie podobne do return, z tą różnicą, że yield zwraca obiekt generatora zamiast wartości. 

Iteratory i obiekty iterowalne w Pythonie

Obiekty iterowalne potrafią zwracać swoje elementy po jednym – można po nich iterować. Popularne wbudowane struktury danych Pythona, takie jak listy, krotki i zbiory, są iterowalne. Inne struktury, jak łańcuchy znaków i słowniki, również nimi są: po stringu można iterować znak po znaku, a po słowniku – po jego kluczach. Zasadniczo każdy obiekt, po którym można iterować w pętli for, traktuj jako iterowalny. 

Przykłady obiektów iterowalnych w Pythonie

Z tych definicji wynika, że wszystkie iteratory są również iterowalne. Jednak nie każdy obiekt iterowalny jest iteratorem. Obiekt iterowalny tworzy iterator dopiero w momencie, gdy po nim iterujemy.

Aby to pokazać, utworzymy listę (iterowalną) i wygenerujemy iterator, wywołując na niej wbudowaną funkcję iter()

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

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

Chociaż sama lista nie jest iteratorem, wywołanie funkcji iter() konwertuje ją na iterator i zwraca obiekt iteratora.

Aby pokazać, że nie wszystkie iterowalne obiekty są iteratorami, utworzymy tę samą listę i spróbujemy wywołać funkcję next(), która zwraca kolejny element iteratora.  

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

W powyższym kodzie widać, że próba wywołania funkcji next() na liście spowodowała TypeError – więcej o tym w artykule Obsługa wyjątków i błędów w Pythonie. Tak się dzieje, ponieważ lista jest obiektem iterowalnym, a nie iteratorem. 

Przykłady iteratorów w Pythonie

Jeśli więc chcemy iterować po liście, musimy najpierw utworzyć obiekt iteratora. Dopiero wtedy możemy sterować iteracją po wartościach listy.

# 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 automatycznie tworzy obiekt iteratora, gdy próbujesz przejść pętlą po obiekcie iterowalnym. 

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

Gdy zostanie przechwycony wyjątek StopIteration, pętla się kończy.

Wartości z iteratora można pobierać tylko od lewej do prawej. Python nie ma funkcji previous(), która pozwalałaby cofać się w iteratorze. 

Leniwa natura iteratorów

Można zdefiniować wiele iteratorów opartych na tym samym obiekcie iterowalnym. Każdy iterator utrzymuje własny stan postępu. Dzięki temu można doprowadzić iterację jednego egzemplarza do końca, podczas gdy inny wciąż pozostaje na początku.

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

Zwróć uwagę, że iterator_b wypisuje pierwszy element sekwencji.

Możemy więc powiedzieć, że iteratory są „leniwe”: po utworzeniu iteratora elementy nie są zwracane, dopóki nie zostaną o nie poproszone. Innymi słowy, elementy naszej listy byłyby zwracane dopiero wtedy, gdy jawnie o nie poprosimy za pomocą next(iter(list_instance))

Można jednak wydobyć wszystkie wartości z iteratora naraz, wywołując na nim wbudowany kontener iterowalny (np. list(), set(), tuple()), co wymusza wygenerowanie wszystkich elementów jednocześnie.

# 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]
"""

Nie jest to zalecane dla dużych iteratorów, ponieważ wymusza wygenerowanie i przetrzymywanie w pamięci wszystkich elementów naraz, co niweczy cel leniwej ewaluacji.

Gdy zbiór danych jest zbyt duży, aby wygodnie zmieścić się w pamięci, albo gdy chcesz leniwie iterować bez pisania pełnej klasy iteratora, zwykle lepszym wyborem jest generator.

Generatory w Pythonie

Najszybszą alternatywą dla implementowania iteratora jest użycie generatora. Choć generatory mogą wyglądać jak zwykłe funkcje Pythona, różnią się od nich. Przede wszystkim obiekt generatora nie zwraca elementów w tradycyjny sposób. Zamiast tego używa słowa kluczowego yield, aby generować elementy na bieżąco. Możemy więc powiedzieć, że generator to szczególny rodzaj funkcji korzystającej z leniwej ewaluacji.

Generatory nie przechowują zawartości w pamięci tak, jak typowe obiekty iterowalne. Na przykład, gdybyśmy chcieli znaleźć wszystkie dzielniki dodatniej liczby całkowitej, zwykle zaimplementowalibyśmy tradycyjną funkcję (więcej o tym w samouczku Funkcje w Pythonie) w następujący sposób:  

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]
"""

Powyższy kod zwraca całą listę dzielników. Zauważ jednak różnicę, gdy zamiast tradycyjnej funkcji użyjemy generatora:

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

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

Ponieważ użyliśmy yield zamiast return, funkcja nie kończy działania po uruchomieniu. W istocie poprosiliśmy Pythona o utworzenie obiektu generatora zamiast tradycyjnej funkcji, co pozwala śledzić stan generatora. 

Dzięki temu możemy wywoływać funkcję next() na leniwym iteratorze i wyświetlać elementy sekwencji po jednym. 

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

Generator można również utworzyć za pomocą wyrażenia generatorowego. Składnia jest podobna do składni list comprehension, z tym że używa nawiasów okrągłych zamiast kwadratowych.

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

Jak działa słowo kluczowe yield w Pythonie

Słowo kluczowe yield steruje przepływem funkcji generatora. Zamiast kończyć działanie funkcji jak przy return, yield zwraca wartość, ale zapamiętuje stan jej zmiennych lokalnych.

Generator zwrócony przez wywołanie yield można przypisać do zmiennej i iterować po nim funkcją next() – to wykona funkcję do momentu napotkania pierwszego słowa kluczowego yield. Gdy natrafimy na yield, wykonywanie funkcji zostaje wstrzymane. W tym momencie stan funkcji jest zapisywany, więc możemy wznowić jej wykonanie w dowolnym momencie. 

Funkcja będzie kontynuować od miejsca wywołania yield. Na przykład: 

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:
"""

W powyższym kodzie nasz generator ma cztery wywołania yield, ale próbujemy wywołać next pięć razy, co skutkuje wyjątkiem StopIteration. Dzieje się tak, ponieważ generator nie jest nieskończoną serią i wywołanie go więcej razy niż przewidziano wyczerpuje generator.

Podsumowanie 

Podsumowując: iteratory to obiekty, po których można iterować, a generatory to specjalne funkcje korzystające z leniwej ewaluacji. Implementując własny iterator, musisz zdefiniować metody __iter__() i __next__(), natomiast generator można zaimplementować za pomocą słowa kluczowego yield w funkcji Pythona lub w wyrażeniu generatorowym. 

Własny iterator może być lepszy od generatora, gdy potrzebujesz obiektu o złożonym zachowaniu utrzymywania stanu lub chcesz udostępnić inne metody poza __next__(), __iter__() i __init__(). Z kolei generator bywa korzystniejszy przy pracy z dużymi zbiorami danych, ponieważ nie przechowuje zawartości w pamięci, lub gdy implementowanie iteratora nie jest konieczne. 

FAQS

Jaka jest różnica między iteratorem a generatorem w Pythonie?

Iteratorem jest każdy obiekt, który implementuje __iter__() i __next__(). Generator to prostszy sposób tworzenia iteratora przy użyciu funkcji ze słowem kluczowym yield. Wszystkie generatory są iteratorami, ale nie wszystkie iteratory są generatorami.

Kiedy powinienem użyć generatora zamiast listy w Pythonie?

Używaj generatora dla dużych lub nieskończonych sekwencji albo gdy ważna jest oszczędność pamięci. Listy trzymają wszystkie elementy w pamięci naraz, a generatory wytwarzają je po jednym. Dla małych zbiorów danych, których będziesz wielokrotnie używać, lista zwykle wystarczy.

Co robi słowo kluczowe yield w Pythonie?

Słowo kluczowe yield zmienia funkcję w generator. Zamiast zwracać wartość i kończyć działanie, yield wstrzymuje funkcję, zwraca wartość i zapamiętuje jej stan, aby przy kolejnym wywołaniu kontynuować wykonanie.

Jak utworzyć generator w Pythonie?

Możesz napisać funkcję, która używa yield zamiast return, albo użyć wyrażenia generatorowego — ta sama składnia co list comprehension, ale z nawiasami okrągłymi, np. (x * 2 for x in range(10)).

Czy generatory są szybsze niż iteratory w Pythonie?

Nie pod względem surowej szybkości, ale są bardziej oszczędne pamięciowo, ponieważ wytwarzają wartości na żądanie. Dla dużych zbiorów danych często przekłada się to na lepszą ogólną wydajność; dla małych różnica jest pomijalna.

Tematy

Najlepsze kursy Pythona

course

Intermediate Python

4 godz.
1.4M
Level up your data science skills by creating visualizations using Matplotlib and manipulating DataFrames with pandas.
Zobacz szczegółyCodestin Search App
Rozpocznij kurs
Zobacz więcejCodestin Search App