This PEP would be great if accepted, it is a natural extension for the generic typing in classes:
my_empty_list = list[int]()
def empty_container[T]() -> list[T]:
return list()
my_empty_container = empty_container[int]() # feels natural but doesn't work ...
But where it excel the most it is in generators, more specifically in consumer generators with send, as they are imposible to type properly.
The most naive example is example is generator equivalent to reduce(operator.add, iter) meaning a generator that sums if int / float, broadcast if np.array and concatenates if str or list:
from typing import Protocol
class SupportsAdd[T](Protocol):
def __add__(self, other: T) -> T: ...
def gen_sum[T: SupportsAdd]() -> Generator[T, T]:
# yield None raises issue in mypy but is never used, so don't do T | None
s = yield None # type: ignore
while True:
s += yield s
# Ideally with this pep we could do:
gen1 = gen_opadd[float]()
next(gen1)
# reveal_type(gen1) = Generator[float, float] # but doesn't work
# reveal_type(gen1.send(1.2)) = float # but doesn't work
gen2 = gen_opadd[str]()
next(gen2)
# reveal_type(gen2.send("2")) = str # but doesn't work
Other example that is not working and maybe doesn’t even need the pep:
def raw[T]() -> Generator[T, T]:
last = yield None # type: ignore (Annoying but neccesary till now)
while True:
# do smthg like print or whatever
last = yield last
raw_procces = raw()
next(raw_procces) # prime generator
b = raw_procces.send(1) # reveal_type -> Unknown , :( when is clearly int
# but at least with the pep we could save the day partially for cases where send has always the same type.
raw_procces = raw[int]()
next(raw_procces) # prime generator
b = raw_procces.send(1) # not working currently
# and maybe even at each call (though i don't expect this to be efficient)
b = raw_procces.send[str]("t") # ?? maybe
I hope this illustrate how useful this syntax would be in the generator world, of course as you can expect everything applies in the same way for AsyncGenerators.
I only wrote naive examples that are not that useful and where the type of the send and yield did not change, but i think the idea is clear, these generators have been a bit overlooked, but would benefit massively from this pep.
Also I’m looking for ideas for how to solve in a elegant manner the # type: ignore in the yield None, so if anyone knows, pls tell me.