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