I once wrote a library of signal processing components based on the premise that the raw input signal is such a sequence, and its concrete type was Iterable[np.ndarray] (iterable of chunks of audio signal). Since the signal is unbounded - we just continue sampling from, say, a microphone forever - the types can't involve finite sequences like lists. A general iterable is works here, and then components that transform the sequence are themselves implemented as generators, or if they are very simple, as generator expressions.
Consider the following function for amplifying a signal:
def amplify(signal: Iterable[np.ndarray], a: float):
return (a*chunk for chunk in signal)
You can flip the whole infinite streams interface and talk about "pushing" chunks around, and it's an esthetic choice.I'm dumbfounded that I have written python for as long as I have without ever encountering this, TIL!
https://lerner.co.il/2020/05/08/making-sense-of-generators-c...
> "The above code looks a bit weird, in that “yield’ is on the right side of an assignment statement. This means that “yield” must be providing a value to the generator. Where is it getting that value from?
Answer: From the “send” method, which can be invoked in place of the “next” function. The “send” method works just like “next”, except that you can pass any Python data structure you want into the generator. And whatever you send to the generator is then assigned to “x”."
Regarding that article specifically I think it could've done better service to 'yield from' had it mentioned recursive generators. One example would be flattening nested lists: have a flatten function that checks if its argument is iterable: if not just yield the thing else yield from flatten for every item in the iterable.
https://twisted.org/documents/21.2.0/api/twisted.internet.de...
Imo it’s a well written, technically accurate article.
They're so powerful in fact, that asyncio is implemented under the hood with a lot of generator cleverness. You rarely see it, but the `__await__` dunder method which powers `await` is just a synchronous function which returns a generator.
Generator expressions are useful for when there's memory constraints that preclude using a list comprehension, but list comprehensions are actually faster because of cPython's internal optimizations.
[0] https://peps.python.org/pep-0255/ [1] https://peps.python.org/pep-0289/