Need to produce values one at a time instead of building a complete collection? Put yield inside a generator function. Each yield provides a value, pauses execution, and lets the generator resume later from the following line. section 7.4.1
Yield perfect squares lazily
def perfect_squares(limit): n = 1 while n <= limit: yield n * n n += 1 sum(perfect_squares(3)) # 14 Calling next repeatedly retrieves 1, 4, and 9. The generator remembers its state between calls, then becomes exhausted when the loop ends. section 7.4.1
Listing 7.10 Creating a generator to calculate the sum of perfect squares
def perfect_squares(limit):
n = 1
while n <= limit:
yield n * n
n += 1
squares_gen = perfect_squares(upper_limit)
sum_gen = sum(squares_gen)
assert sum_gen == sum_list == 333333833333500000
Inspect the complete generator that calculates the sum of perfect squares and compares it with an equivalent list-based result. section 7.4.1
Keep these usage distinctions in mind:
- Use next(generator) to resume execution manually; iteration constructs call next behind the scenes. section 7.4.1
- Treat yield differently from return: return ends execution, while yield temporarily gives control back to the caller. section 7.4.1
- Remember that consumed values do not reappear; calling next three times before sum causes sum to begin with the next value. section 7.4.3
- Prefer a generator expression when the generation logic is straightforward, using parentheses rather than square brackets. section 7.4.3









