Type Hinting Generators in Python Using the typing Module
When working with generators, the typing
module provides tools to define the types of the values they yield, accept, or return.
In this tutorial, you’ll learn how to use the Python typing
module to annotate generators.
Basic Generator Type Hinting
You can specify a generator’s yield, send, and return types using Generator
.
from typing import Generator def employee_names() -> Generator[str, None, None]: names = ["Ahmed", "Salma", "Khaled"] for name in names: yield name # Consume the generator for employee in employee_names(): print(employee)
Output:
Ahmed Salma Khaled
The generator yields strings, defined by Generator[str, None, None]
.
The send
and return
types are None
because the generator doesn’t accept or return values.
When only the yield type matters, use Iterable
instead of Generator
.
from typing import Iterable def employee_names() -> Iterable[str]: return (name for name in ["Ahmed", "Salma", "Khaled"]) for employee in employee_names(): print(employee)
Output:
Ahmed Salma Khaled
Iterable[str]
implies an iterator that produces strings without specifying send or return types.
Yield Type Annotations
You can annotate the type of values yielded by a generator.
from typing import Generator def employee_salaries() -> Generator[int, None, None]: for salary in [5000, 7000, 6000]: yield salary for salary in employee_salaries(): print(salary)
Output:
5000 7000 6000
The generator yields integers representing employee salaries.
You can annotate with a union if a generator yields multiple types.
from typing import Generator, Union def mixed_values() -> Generator[Union[int, str], None, None]: yield 42 yield "Maha" yield 73 for value in mixed_values(): print(value)
Output:
42 Maha 73
The Union[int, str]
type accounts for the generator yielding both integers and strings.
Send Type Annotations
You can annotate the type accepted by send()
.
from typing import Generator def feedback() -> Generator[str, int, None]: while True: received = yield "Waiting for feedback..." print(f"Received feedback score: {received}") gen = feedback() print(next(gen)) gen.send(8)
Output:
Waiting for feedback... Received feedback score: 8
The send()
method accepts integers, as specified by Generator[str, int, None]
.
Return Type Annotations
You can use Generator
to indicate the return value after StopIteration
.
from typing import Generator def calculate_bonus() -> Generator[int, None, float]: yield 500 yield 700 return 100.0 gen = calculate_bonus() for bonus in gen: print(bonus) try: next(gen) except StopIteration as e: print(f"Bonus calculation complete: {e.value}")
Output:
500 700 Bonus calculation complete: 100.0
The return value 100.0
is specified as the third argument of Generator
.
Asynchronous Generators and Type Hinting
Async generators use AsyncGenerator
for type hinting.
from typing import AsyncGenerator async def async_employee_names() -> AsyncGenerator[str, None]: for name in ["Aya", "Nour", "Omar"]: yield name import asyncio async def main(): async for name in async_employee_names(): print(name) asyncio.run(main())
Output:
Aya Nour Omar
Async generators yield values asynchronously, annotated with AsyncGenerator
.
Generator Comprehensions and Type Hinting
You can use Generator
for comprehensions.
from typing import Generator numbers: Generator[int, None, None] = (x * 2 for x in range(3)) for num in numbers: print(num)
Output:
0 2 4
The generator comprehension is explicitly typed as Generator[int, None, None]
.
Recursive Generators and Type Hinting
Use recursion for generators producing nested data.
from typing import Generator def nested_numbers(level: int) -> Generator[int, None, None]: if level == 0: yield 0 else: yield level yield from nested_numbers(level - 1) for num in nested_numbers(3): print(num)
Output:
3 2 1 0
The generator recursively yields integers by calling itself.
Type Hinting Infinite Generators
Annotate infinite generators to handle non-terminating cases.
from typing import Generator def infinite_counter() -> Generator[int, None, None]: count = 0 while True: yield count count += 1 counter = infinite_counter() for _ in range(5): print(next(counter))
Output:
0 1 2 3 4
The infinite generator continuously yields integers, with no end condition.
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.