如何确定Python中任意Generator的yield/send/return值及类型提示方法
Let's break down how to figure out the three type parameters for typing.Generator and apply that to your pathlib.Path.glob example.
First, a quick recap of what each parameter in Generator[YieldType, SendType, ReturnType] means:
- YieldType: The type of value the generator produces each time it
yields. This is what you get when you callnext()on the generator, or when iterating over it. - SendType: The type of value the generator accepts via the
send()method. This only matters if the generator uses syntax likereceived_value = yield some_valueto accept input during iteration. - ReturnType: The type of value the generator returns when it exits (via an explicit
returnstatement). If the generator doesn't have an explicit return, this defaults toNone.
Applying This to Your pathlib.Path.glob Example
The generator returned by Path.glob() is a simple iterator—it only yields pathlib.Path objects, doesn't accept any values via send(), and doesn't return a meaningful value when it finishes iterating. Here's how to fill in the type hints correctly:
from typing import Generator import pathlib def list_of_paths(paths: Generator[pathlib.Path, None, None]) -> list[pathlib.Path]: return list(paths) path_list = list_of_paths(paths=pathlib.Path('.').glob('*'))
As a helpful side note: since list() works with any Iterable, you could make this function more flexible by using Iterable[pathlib.Path] instead of Generator. This lets you pass in lists, tuples, or any other iterable of paths, not just generators:
from typing import Iterable import pathlib def list_of_paths(paths: Iterable[pathlib.Path]) -> list[pathlib.Path]: return list(paths)
How to Determine These Types for Any Generator
YieldType:
- For standard library functions like
glob, check the built-in type annotations (even if the prose documentation doesn't spell it out, the type hints are usually present). - At runtime, you can call
type(next(generator))—just be aware this consumes the first yielded value, so you might want to create a fresh generator instance for this check. - Use a type checker like mypy or pyright—they'll automatically infer this type when analyzing your code.
- For standard library functions like
SendType:
- Look at the generator's source code: if it never uses
received_value = yield ...syntax, it doesn't accept input viasend(), so this type isNone(sending anything other thanNoneto such a generator will throw an error). - If the generator does accept input, the type of
received_valueis your SendType.
- Look at the generator's source code: if it never uses
ReturnType:
- Check if the generator has an explicit
return some_valuestatement—if so, the type ofsome_valueis your ReturnType. - If there's no explicit return, this defaults to
None. To confirm at runtime, catch theStopIterationexception raised when the generator finishes; itsvalueattribute holds the return value:def sample_generator(): yield "hello" return "finished" gen = sample_generator() next(gen) # Consume the yielded value try: next(gen) except StopIteration as e: print(type(e.value)) # Output: <class 'str'>
- Check if the generator has an explicit
内容的提问来源于stack exchange,提问作者baxx

