12.2. Generator Function

  • Processes one element at a time

  • Does not remember previous element

  • Does not know next element

  • Can be used only once

  • Save memory (does not require more memory for processing large data)

  • Values are computed on demand

  • No need to store all values in memory

  • Uses around 10% more CPU than regular processing

  • Typical usage: streams, processing larger than memory files or data

  • Cannot use len() as of generators don't have length

  • Previous element is overridden by current on next()

  • Functions (list, dict, tuple, frozenset, set, sum, all, any, etc) will evaluate generator instantly

12.2.1. Plain Function

  • Plain function returns plain object

>>> def run():
...     return 1
>>> type(run)
<class 'function'>
>>> type(run())
<class 'int'>

12.2.2. Generator Function

  • Generator function returns generator object

>>> def run():
...     yield 1
>>> type(run)
<class 'function'>
>>> type(run())
<class 'generator'>

12.2.3. Yield vs. Return

  • After return function stops

  • After yield function pauses

>>> def run():
...     return 1
...     return 2
>>> def run():
...     yield 1
...     yield 2

12.2.4. Lazy Evaluation

  • After yield function pauses

  • Calling next() resumes function until next yield

  • After last yield raises StopIteration

>>> def run():
...     yield 1
...     yield 2
>>> result = run()
>>> next(result)
1
>>> next(result)
2
>>> next(result)
Traceback (most recent call last):
StopIteration

12.2.5. Instant Evaluation

  • Using list() will evaluate generator instantly

  • Functions (list, tuple, set, dict, sum, min, max, all, any, etc) will evaluate generator instantly

>>> def run():
...     yield 1
...     yield 2
>>> result = run()
>>> tuple(result)
(1, 2)

12.2.6. Assignments

# %% About
# - Name: Generator Function Plain
# - Difficulty: easy
# - Lines: 2
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create plain function `myfunc()` that returns `1`
# 2. Run doctests - all must succeed

# %% Polish
# 1. Stwórz zwykłą funkcję `myfunc()`, która zwraca `1`
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> myfunc()
# 1

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 9), \
'Python has an is invalid version; expected: `3.9` or newer.'

>>> from sys import getsizeof
>>> from inspect import isfunction, isgeneratorfunction, isgenerator

>>> isfunction(myfunc)
True

>>> isgeneratorfunction(myfunc)
False

>>> result = myfunc()
>>> isgenerator(result)
False

>>> result
1
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
a: Callable[[], int]

# %% Data

# %% Result

# %% About
# - Name: Generator Function Generator
# - Difficulty: easy
# - Lines: 2
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create generator function `run()` that yields `1`
# 2. Run doctests - all must succeed

# %% Polish
# 1. Stwórz funkcję generatorową `run()`, która yielduje `1`
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> run()
# <generator object a at 0x...>
#
# >>> result = run()
# >>> next(result)
# 1
# >>> next(result)
# Traceback (most recent call last):
# StopIteration

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 9), \
'Python has an is invalid version; expected: `3.9` or newer.'

>>> from sys import getsizeof
>>> from inspect import isfunction, isgeneratorfunction, isgenerator

>>> isfunction(run)
True

>>> isgeneratorfunction(run)
True

>>> result = run()

>>> isgenerator(result)
True

>>> result  # doctest: +ELLIPSIS
<generator object run at 0x...>

>>> next(result)
1

>>> next(result)
Traceback (most recent call last):
StopIteration
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
run: Callable[[], int]

# %% Data

# %% Result

# %% About
# - Name: Iterator About Yield
# - Difficulty: easy
# - Lines: 4
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `run() -> Iterator[int]`
# 2. Function yields 1
# 3. Function yields 2
# 4. Function yields 3
# 5. Use `yield` keyword
# 6. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `run() -> Iterator[int]`
# 2. Funkcja jelduje 1
# 3. Funkcja jelduje 2
# 4. Funkcja jelduje 3
# 5. Użyj słowa kluczowego `yield`
# 6. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> result = run()
#
# >>> next(result)
# 1
#
# >>> next(result)
# 2
#
# >>> next(result)
# 3
#
# >>> next(result)
# Traceback (most recent call last):
# StopIteration

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 9), \
'Python has an is invalid version; expected: `3.9` or newer.'

>>> from inspect import isfunction
>>> assert isfunction(run)

>>> result = run()
>>>
>>> next(result)
1
>>> next(result)
2
>>> next(result)
3
>>> next(result)
Traceback (most recent call last):
StopIteration
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports

# %% Types
from typing import Callable, Iterator
run: Callable[[], Iterator[int]]

# %% Data

# %% Result
def run():
    ...

# %% About
# - Name: Iterator About For-Yield
# - Difficulty: easy
# - Lines: 3
# - Minutes: 3

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `run() -> Iterator[int]`
# 2. Function yields 1
# 3. Function yields 2
# 4. Function yields 3
# 5. Use `yield` keyword
# 6. Use `for` loop
# 7. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `run() -> Iterator[int]`
# 2. Funkcja jelduje 1
# 3. Funkcja jelduje 2
# 4. Funkcja jelduje 3
# 5. Użyj słowa kluczowego `yield`
# 6. Użyj pętli `for`
# 7. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> result = run()
#
# >>> next(result)
# 1
#
# >>> next(result)
# 2
#
# >>> next(result)
# 3
#
# >>> next(result)
# Traceback (most recent call last):
# StopIteration

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 9), \
'Python has an is invalid version; expected: `3.9` or newer.'

>>> from inspect import isfunction
>>> assert isfunction(run)

>>> result = run()
>>>
>>> next(result)
1
>>> next(result)
2
>>> next(result)
3
>>> next(result)
Traceback (most recent call last):
StopIteration
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports

# %% Types
from typing import Callable, Iterator
run: Callable[[], Iterator[int]]

# %% Data

# %% Result
def run():
    ...