Nearby lessons

114 of 159

Python - Generators

📌 What You Will Learn
  • Understand what a generator function is
  • Know how the yield keyword differs from return
  • Use next() and for loops with generator objects
  • Understand how generator state is preserved between yields
  • Build generators with parameters, sequences, and the Fibonacci series

What is a Generator Function?

In Python, a Generator Function is a special type of function that generates values one at a time instead of returning all values at once.

A Normal Function uses the return statement to return a value and terminate the function.

A Generator Function uses the yield keyword to produce a value and temporarily pause its execution.

When a Generator Function is called, it does not immediately execute the complete function. Instead, it returns a special object called a Generator Object.

The values from the Generator Object can be retrieved one at a time.

Why Do We Need Generator Functions?

Suppose we need to process millions of records.

If we store all records inside a list, the complete list must be stored in memory. This can consume a large amount of memory.

A Generator Function solves this problem by generating one value at a time.

Therefore, Generator Functions are useful when:

  • Working with large datasets.
  • Reading large files.
  • Generating large sequences of numbers.
  • Processing streaming data.
  • Reducing memory consumption.
  • Generating values only when they are required.

The yield Keyword

The yield keyword is the most important part of a Generator Function.

It is similar to the return statement because both can send a value back to the caller. However, there is an important difference.

  • The return statement terminates the function completely.
  • The yield statement pauses the function and saves its current state.

When the next value is requested, execution continues from the statement immediately after the previous yield.

Syntax

🐍Code Cell
1def generator_name():
2 yield value
Output
No output captured.

First Generator Function

🐍Code Cell
1def display():
2 yield 10
3 yield 20
4 yield 30
5 
6result = display()
7 
8print(result)
Output
No output captured.

Explanation

The function display() contains three yield statements.

Because the function contains yield, Python automatically treats it as a Generator Function.

When display() is called, the function does not return all three values immediately. Instead, it returns a Generator Object.

The exact memory address displayed in the Generator Object may be different each time the program runs.

The Generator Object

A Generator Object represents the sequence of values produced by a Generator Function.

The Generator Object is also an iterator. Therefore, we can retrieve values from it using:

  • The next() function.
  • A for loop.

Generator values are produced only when requested. This behaviour is known as Lazy Evaluation.

Using next() with a Generator

🐍Code Cell
1def display():
2 yield 10
3 yield 20
4 yield 30
5 
6result = display()
7 
8print(next(result))
9print(next(result))
10print(next(result))
Output
10
20
30

Step-by-Step Execution

The first call to next(result) starts the Generator Function. Execution continues until the first yield statement is reached. The value 10 is produced and the function pauses.

The second call continues execution from the previous position and produces 20. The third call produces 30.

Function Call Action Result
display() Creates Generator Object No value generated yet
First next() Executes until first yield 10
Second next() Continues until second yield 20
Third next() Continues until third yield 30

What is StopIteration?

After all values have been generated, calling next() again raises a StopIteration exception.

🐍Code Cell
1def display():
2 yield 10
3 yield 20
4 
5result = display()
6 
7print(next(result))
8print(next(result))
9print(next(result))
Output
10
20
StopIteration

Using a Generator with a for Loop

A for loop automatically retrieves values from the Generator Object one at a time. It internally handles the StopIteration exception, so using a for loop is often easier than manually calling next().

🐍Code Cell
1def display():
2 yield 10
3 yield 20
4 yield 30
5 
6for value in display():
7 print(value)
Output
10
20
30

Normal Function vs Generator Function

Normal Function Generator Function
Uses return. Uses yield.
Returns a value and terminates. Produces a value and pauses.
Does not preserve execution state after returning. Preserves execution state between yields.
Normally executes when called. Calling it creates a Generator Object; execution starts when iteration begins.
Usually returns the complete result. Generates values one at a time.
May require more memory when returning large collections. Memory efficient for large sequences.

return vs yield

return yield
Used in Normal Functions. Used in Generator Functions.
Terminates the function. Pauses the function.
Returns a value directly. Produces a value when requested.
Function state is not resumed after returning. Function state is preserved and execution can continue.

How a Generator Function Works

Step Description
1 A Generator Function is defined using one or more yield statements.
2 Calling the function creates a Generator Object.
3 The first value is requested using next() or iteration.
4 The function executes until it reaches yield.
5 The value is produced and execution pauses.
6 The next request resumes execution from the previous position.
7 When the function finishes, iteration stops.

Multiple yield Statements

A Generator Function can contain multiple yield statements. Each yield produces one value and temporarily pauses the function.

🐍Code Cell
1def numbers():
2 yield 10
3 yield 20
4 yield 30
5 yield 40
6 
7result = numbers()
8 
9print(next(result))
10print(next(result))
11print(next(result))
12print(next(result))
Output
10
20
30
40

Program: Understanding Pause and Resume

This program shows exactly where execution resumes after each yield.

🐍Code Cell
1def demo():
2 print("Start")
3 
4 yield 10
5 
6 print("After First Yield")
7 
8 yield 20
9 
10 print("After Second Yield")
11 
12 yield 30
13 
14result = demo()
15 
16print(next(result))
17print(next(result))
18print(next(result))
Output
Start
10
After First Yield
20
After Second Yield
30

Explanation

When the first next() is called, the function starts execution. It prints Start and reaches yield 10. The value 10 is produced and the function pauses.

When the second next() is called, execution resumes after yield 10. It prints After First Yield and produces 20.

The third next() resumes the function again and produces 30.

Generator Function with Parameters

Just like Normal Functions, Generator Functions can also accept parameters. The parameter values can be used to control which values the Generator produces.

🐍Code Cell
1def numbers(n):
2 i = 1
3 
4 while i <= n:
5 yield i
6 i = i + 1
7 
8for value in numbers(5):
9 print(value)
Output
1
2
3
4
5

Program: Generate Even Numbers

🐍Code Cell
1def evenNumbers(n):
2 i = 2
3 
4 while i <= n:
5 yield i
6 i = i + 2
7 
8for value in evenNumbers(10):
9 print(value)
Output
2
4
6
8
10

Program: Generate Odd Numbers

🐍Code Cell
1def oddNumbers(n):
2 i = 1
3 
4 while i <= n:
5 yield i
6 i = i + 2
7 
8for value in oddNumbers(10):
9 print(value)
Output
1
3
5
7
9

Program: Generate Squares

🐍Code Cell
1def squares(n):
2 i = 1
3 
4 while i <= n:
5 yield i * i
6 i = i + 1
7 
8for value in squares(5):
9 print(value)
Output
1
4
9
16
25

Program: Generate a Countdown

🐍Code Cell
1def countdown(n):
2 while n > 0:
3 yield n
4 n = n - 1
5 
6for value in countdown(5):
7 print(value)
Output
5
4
3
2
1

Program: Generator Using range()

🐍Code Cell
1def numbers(n):
2 for i in range(1, n + 1):
3 yield i
4 
5for value in numbers(5):
6 print(value)
Output
1
2
3
4
5

Program: Convert Generator Values to a List

A Generator Object can be converted into a list using list().

However, converting a Generator into a list generates and stores all values in memory, which reduces the memory-saving advantage of the Generator.

🐍Code Cell
1def numbers():
2 yield 10
3 yield 20
4 yield 30
5 yield 40
6 
7result = numbers()
8 
9print(list(result))
Output
[10, 20, 30, 40]

Generator Objects Can Be Exhausted

A Generator Object produces each value only once. After all values have been consumed, the same Generator Object cannot automatically start again.

🐍Code Cell
1def numbers():
2 yield 10
3 yield 20
4 yield 30
5 
6result = numbers()
7 
8print(list(result))
9 
10print(list(result))
Output
[10, 20, 30]
[]

Creating a New Generator Object

To iterate again, a new Generator Object must be created by calling the Generator Function again. Each call creates an independent Generator Object.

🐍Code Cell
1def numbers():
2 yield 10
3 yield 20
4 yield 30
5 
6result1 = numbers()
7result2 = numbers()
8 
9print(list(result1))
10 
11print(list(result2))
Output
[10, 20, 30]
[10, 20, 30]

Program: Fibonacci Sequence Using a Generator

🐍Code Cell
1def fibonacci(n):
2 a = 0
3 b = 1
4 
5 count = 0
6 
7 while count < n:
8 yield a
9 
10 a, b = b, a + b
11 
12 count = count + 1
13 
14for value in fibonacci(10):
15 print(value)
Output
0
1
1
2
3
5
8
13
21
34

Explanation

The Generator produces Fibonacci numbers one at a time. The variables a and b store the current and next Fibonacci values.

After each yield, the Generator preserves these variable values. When execution resumes, the next Fibonacci number is calculated.

This approach is useful because a complete list of Fibonacci numbers does not need to be created before processing begins.

How State is Preserved

The Generator automatically remembers its complete state between yield statements.

Generator Feature Description
Local Variables Their values are preserved between yield statements.
Execution Position The position where the function paused is remembered.
Next Request Execution resumes from the previous position.
Completion The Generator becomes exhausted after the function finishes.

Advantages of Generator Functions

  • Values are generated only when required.
  • Memory consumption is reduced.
  • The execution state is automatically preserved.
  • Large sequences can be processed efficiently.
  • Generators work directly with for loops.
  • Generator code can be simpler than creating custom iterator classes.
  • Useful for processing large datasets and streaming data.
📝 Key Takeaways
  • A generator function uses yield instead of return to produce values one at a time
  • Calling a generator function returns a generator object, it does not run the function body
  • next() runs the function until the next yield; StopIteration is raised when values end
  • The generator preserves its local variables and execution position between yields
  • Generators are memory efficient because values are generated only when requested

🧠 Test Your Knowledge

10 Questions
Progress: 0 / 10