Python Generators

In this section, we'll explore Python generators—an essential Python feature that helps you create memory-efficient iterators. Generators are used for iterating over data, especially when working with large datasets. Let’s dive into the syntax, how to create a generator, and practical usage examples.



Understanding Generator Syntax

A generator is a special type of function in Python that allows you to return an iterable set of items one at a time using the yield keyword. The yield keyword is what turns a function into a generator, enabling it to return values one at a time.

python
def my_generator():
    yield 1
    yield 2
    yield 3

gen = my_generator()  # Create generator object
print(next(gen))  # Output: 1
print(next(gen))  # Output: 2
print(next(gen))  # Output: 3

In this example, the my_generator function is a generator that yields values one by one. When the generator is called, it returns an iterator that can be iterated over using next() or in a for loop.

Using the yield Keyword

The yield keyword pauses the function’s execution and sends a value to the caller. The state of the function is saved so that when you call next() again, it picks up where it left off.

python
def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

counter = count_up_to(5)
print(next(counter))  # Output: 1
print(next(counter))  # Output: 2

In this example, the count_up_to generator yields numbers from 1 up to the specified maximum. Each time you call next(), the function resumes from where it last yielded.

Using yield in Loops

A generator can be used inside loops to yield multiple values in sequence. This allows for efficient iteration over large datasets.

python
def even_numbers(limit):
    for number in range(2, limit, 2):
        yield number

for even in even_numbers(10):
    print(even)

# Output:
# 2
# 4
# 6
# 8
        

This example defines a generator that yields even numbers up to a specified limit. Using a for loop, the generator is iterated over efficiently.


Example 1: Fibonacci Sequence Generator

The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones. Below is a generator function that yields values from the Fibonacci sequence:

python
def fibonacci(n):
  a, b = 0, 1
  for _ in range(n):
      yield a
      a, b = b, a + b

for num in fibonacci(10):
  print(num)

How It Works:

  • def fibonacci(n): defines a generator function that takes one parameter, n, which specifies how many Fibonacci numbers to generate.
  • a, b = 0, 1: initializes the first two numbers in the sequence.
  • yield a: yields the current value of a each iteration.
  • a, b = b, a + b: updates the values to the next pair in the sequence.
  • for num in fibonacci(10): loops through the first 10 numbers of the Fibonacci sequence and prints each one.

Output:

0
1
1
2
3
5
8
13
21
34

Example 2: Squares of Numbers Generator

This generator yields the square of each number from 1 up to a given limit. It's a simple way to understand how yield works with mathematical operations.

python
def square_numbers(n):
  for i in range(1, n + 1):
      yield i * i

for square in square_numbers(5):
  print(square)

How It Works:

  • def square_numbers(n): defines a generator function that takes a single argument n.
  • for i in range(1, n + 1): uses Python’s built-in range() function to create a sequence of numbers from 1 to n. Since range() excludes the stop value, we use n + 1 to include n in the iteration.
  • yield i * i: yields the square of each number from 1 to n.
  • for square in square_numbers(5): prints the squares from 1 to 5.

Output:

1
4
9
16
25

Frequently Asked Questions

What is a generator in Python?

A generator is a type of iterable in Python that yields one value at a time using the yield keyword, making it ideal for large datasets or streams.


How does the yield keyword work?

The yield keyword pauses the generator function and saves its execution state. When the generator resumes, it picks up right where it left off.


What's the difference between yield and return?

return exits the function and provides a single result. yield produces a sequence of results over time and allows the function to resume.


Can generators be used in loops?

Absolutely! Generators are commonly used with for loops to iterate over values one at a time, especially when dealing with large or dynamic data.


Are generators more memory-efficient than lists?

Yes. Unlike lists, which load all values into memory, generators produce values on the fly, making them highly memory-efficient.



What's Next?

In the next section, you'll learn what closures are, how to create them, and where they’re commonly used in real-world Python code.