Generators yield values one at a time instead of returning a complete list. They use constant memory regardless of dataset size.
def read_large_file(path): for line in open(path): yield line. Each next() call resumes after the last yield.
Generator expressions: (x**2 for x in range(1000000)). Unlike list comprehensions, they produce values on demand.
yield from delegates to sub-generators. This simplifies composing generators.
Generators are fundamental to Python iterator protocol. Understanding them helps you write memory-efficient data pipelines.