The most common application is iteration (lazy producers or transformers), but they're also used for their ability to suspend and resume function execution (interruptible functions) e.g.
- pytest fixtures use generators to setup, allow the test to run (yielding a value or not), and teardown
- contextlib.contextmanager uses generators for similar purposes of entering a context, allowing the wrapped code to run, and then exiting the context
They can also act as cheap state managers, especially with the ability to inject data back into the generator, so they can be used to implement a multi-step function where the user needs multiple points of interaction, without needing a bunch of callbacks, or complicated state management (especially without the benefit of sum types or static state machines)