ruk·si

🐍 Python
Generators

Updated at 2018-06-10 08:55

Functions that use yield keyword are generators. Generators can be used to create iterators and coroutines. Generators will raise StopIteration exception after control flow leaves the generator function.

from typing import Iterable

def repeat_four_times(value: str) -> Iterable[str]:
    yield value
    yield value
    yield value
    yield value

for item in repeat_four_times('Hi'):
    assert item == 'Hi'  # this will be called 4 times

iterator = repeat_four_times('Hello')
assert next(iterator) == 'Hello'
assert next(iterator) == 'Hello'
assert next(iterator) == 'Hello'

for item in iterator:
    assert item == 'Hello'  # this will be called only once
from typing import Iterable

logs = [
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    'Sed vel justo eget risus ullamcorper efficitur sollicitudin et python.',
    'Etiam et justo eget tellus sagittis volutpat.',
    'Curabitur molestie nulla eu augue aliquet, ut interdum nisl pharetra.',
    'Donec eu mauris sed nulla accumsan venenatis.',
    'Curabitur ut odio vehicula, python nisi nec, iaculis nisi.',
    'Maecenas eget velit eu est ultricies aliquet ut eu mi.',
]

def grep(pattern: str, lines: Iterable[str]) -> Iterable[str]:
    for line in lines:
        if pattern in line:
            yield line

python_logs = list(grep('python', logs))

assert len(python_logs) == 2
for log in python_logs:
    assert 'python' in log

You can chain generators.

from typing import Iterable

def integers() -> Iterable[int]:
    for number in range(1, 10):
        yield number

def squared(integers: Iterable[int]) -> Iterable[int]:
    for number in integers:
        yield number * number

def negated(integers: Iterable[int]) -> Iterable[int]:
    for number in integers:
        yield -number

assert list(squared([2, 4])) == [4, 16]
assert list(squared(integers())) == [1, 4, 9, 16, 25, 36, 49, 64, 81]
assert list(negated(squared(integers()))) == [-1, -4, -9, -16, -25, -36, -49, -64, -81]

Generators are commonly typed as Iterable. Generator type is used if you use coroutine methods like send and close.

Generator[yield_type, send_type, return_type]

Source

  • Python Tricks The Book, Dan Bader
  • Fluent Python, Luciano Ramalho