10.1. Iterator About

  • 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

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

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

iterable

An object supporting iteration. To create iterable class must implement Iterable protocol, to has __iter__() method.

iterator

An iterable object. To create iterator class must implement Iterator protocol, to has __iter__() and __next__() method.

10.1.1. Examples

  • reversed(sequence, /)

  • range(start=0, stop, step=1), count

  • enumerate(iterable, start=0)

  • zip(*iterables, strict=False), zip_longest

  • map(func, iterables*), starmap

  • filter(func, iterable)

  • chain(*iterables)

  • permutations(iterable, r=None)

  • product(*iterables, repeat=1)

  • cycle(iterable, /)

10.1.2. Plain Function

  • Plain function returns plain object

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

10.1.3. Generator Function

  • Generator function returns generator object

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

10.1.4. Yield vs. Return

  • After return function stops

  • After yield function pauses

We want to return three values from a function. We cannot use return keyword three times, because function will stop being executed after encountering first return:

>>> def run():
...     return 1
...     return 2  # this will never be executed
...     return 3  # this will never be executed

In order to do so, we can return one list of three values:

>>> def run():
...     return [1, 2, 3]

Or we can yield each value:

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

10.1.5. Lazy Evaluation

  • After yield function pauses

  • Calling next() resumes function until next yield

  • After last yield raises StopIteration

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

10.1.6. 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
...     yield 3
>>>
>>>
>>> result = run()
>>> list(result)
[1, 2, 3]

10.1.7. Iterate

>>> def run():
...     yield 1
...     yield 2
...     yield 3
>>>
>>>
>>> for result in run():
...     print(result)
1
2
3

10.1.8. Assignments

# %% 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():
    ...

# %% About
# - Name: Iterator About Adult-List
# - Difficulty: easy
# - Lines: 6
# - 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 `adults(users) -> list[str]`
# 2. Function returns firstnames of adult users (age >= 18)
# 3. Do not use `yield` keyword
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `adults(users) -> list[str]`
# 2. Funkcja zwraca imiona użytkowników pełnoletnich (wiek >= 18)
# 3. Nie używaj słowa kluczowego `yield`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> list(adults(users))
# ['Alice', 'Bob', 'Carol', 'Dave', 'Eve']

# %% 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(adults)

>>> list(adults(users))
['Alice', 'Bob', 'Carol', 'Dave', 'Eve']
"""

# %% 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
adults: Callable[[list[tuple[str,str,int]]], list[str]]

# %% Data
DATA = [
    ('firstname', 'lastname', 'age'),
    ('Alice', 'Apricot', 30),
    ('Bob', 'Blackthorn', 31),
    ('Carol', 'Corn', 32),
    ('Dave', 'Durian', 33),
    ('Eve', 'Elderberry', 34),
    ('Mallory', 'Melon', 15),
]

header, *users = DATA

# %% Result
def adults(users):
    ...

# %% About
# - Name: Iterator About Adult-Iterator
# - Difficulty: easy
# - Lines: 4
# - 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 `adults(users) -> Iterator[int]`
# 2. Function returns firstnames of adult users (age >= 18)
# 3. Use `yield` keyword
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `adults(users) -> Iterator[int]`
# 2. Funkcja zwraca imiona użytkowników pełnoletnich (wiek >= 18)
# 3. Użyj słowa kluczowego `yield`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected
# >>> list(adults(users))
# ['Alice', 'Bob', 'Carol', 'Dave', 'Eve']

# %% 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(adults)

>>> list(adults(users))
['Alice', 'Bob', 'Carol', 'Dave', 'Eve']
"""

# %% 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
adults: Callable[[list[tuple[str,str,int]]], Iterator[int]]

# %% Data
DATA = [
    ('firstname', 'lastname', 'age'),
    ('Alice', 'Apricot', 30),
    ('Bob', 'Blackthorn', 31),
    ('Carol', 'Corn', 32),
    ('Dave', 'Durian', 33),
    ('Eve', 'Elderberry', 34),
    ('Mallory', 'Melon', 15),
]

header, *users = DATA

# %% Result
def adults(users):
    ...