Start here. This is the direct spoken answer to practice first.
Overview
Generators are useful because they express stateful lazy iteration without manually implementing the iterator protocol.
A function containing yield returns a generator iterator when called. The body does not run to completion immediately. Each request for the next value resumes execution until the next yield, preserving local state between resumptions. When the function returns, iteration ends. Generators are useful for pipelines, large inputs, and values produced over time because callers can process items without first building the entire result in memory.