Python Generators – Yield, Syntax & Examples

Introduction

When working with large datasets in Python, storing all values in memory at once can be inefficient and sometimes impossible due to memory limitations. To solve this problem, Python provides a powerful feature called Generators.

Generators are special functions that allow you to generate values one at a time instead of creating and storing the entire sequence in memory. They are memory-efficient, faster for large datasets, and widely used in data processing, file handling, web scraping, and machine learning applications.

For example, instead of creating a list containing one million numbers, a generator can produce each number only when needed.

What are Python Generators?

A generator is a special type of function that returns an iterator and generates values lazily (on demand).

Instead of using return a generator uses yield.

Example


def numbers():
    yield 1
    yield 2
    yield 3

Usage:


num = numbers()
print(next(num))

Output:

1

The generator produces one value at a time.

Why Use Generators?

Generators provide several advantages.

1. Memory Efficient

They do not store all values in memory.

2. Faster Execution

Values are generated only when needed.

3. Lazy Evaluation

Computations occur on demand.

4. Suitable for Large Data

Ideal for processing large files and datasets.

5. Easy to Implement

Simpler than creating custom iterator classes.

Generator vs Normal Function

Normal Function


def show_numbers():
    return [1, 2, 3]

Usage:


print(show_numbers())

Output:

[1, 2, 3]

The entire list is created in memory.

Generator Function


def show_numbers():
    yield 1
    yield 2
    yield 3

Usage:


numbers = show_numbers()
print(next(numbers))

Output:

1

Values are generated one at a time.

Syntax

Basic syntax:


def generator_name():
    yield value

Example:


def fruits():
    yield "Apple"
    yield "Banana"
    yield "Mango"

Usage:


fruit = fruits()
print(next(fruit))

Output:

Apple

Understanding the yield Keyword

The yield keyword is the heart of generators.

When Python encounters yield:

  1. It returns the value.
  2. It pauses the function.
  3. It saves the current state.
  4. Execution resumes from the same point later.

Example:


def demo():
    print("First")
    yield 1
    print("Second")
    yield 2

Usage:


obj = demo()
print(next(obj))
print(next(obj))

Output:

First
1
Second
2

Notice that the function resumes where it previously stopped.

Creating a Simple Generator

Example:


def count():
    yield 1
    yield 2
    yield 3
    yield 4
    yield 5

Usage:


counter = count()
for num in counter:
    print(num)

Output:

1
2
3
4
5

Using next() with Generators

Generators produce values one at a time.

Example:


def numbers():
    yield 10
    yield 20
    yield 30

Usage:


obj = numbers()
print(next(obj))
print(next(obj))
print(next(obj))

Output:

10
20
30

StopIteration Exception

When all values are exhausted, Python raises:


StopIteration

Example:


def numbers():
    yield 1

Usage:


obj = numbers()
print(next(obj))
print(next(obj))

Output:

1
StopIteration

Generator with Loops

Generators often use loops to generate values dynamically.

Example:


def countdown(n):
    while n > 0:
        yield n
        n -= 1

Usage:


for num in countdown(5):
    print(num)

Output:

5
4
3
2
1

Generator for Even Numbers

Example:


def even_numbers(limit):
    for num in range(limit):
        if num % 2 == 0:
            yield num

Usage:


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

Output:

0
2
4
6
8

Generator Expressions

Python supports generator expressions similar to list comprehensions.

List Comprehension


numbers = [x*x for x in range(5)]
print(numbers)

Output:

[0, 1, 4, 9, 16]

Generator Expression


numbers = (x*x for x in range(5))
print(numbers)

Output:

<generator object>

Usage:


for num in numbers:
    print(num)

Output:

0
1
4
9
16

Generator Expression vs List Comprehension

Feature Generator Expression List Comprehension
Memory Usage Low Higher
Evaluation Lazy Immediate
Syntax () []
Performance Better for large data Better for small data
Returns Generator Object List

Real-Life Examples:

1. Reading Large Files

Without Generator:


file = open("data.txt")
lines = file.readlines()

Problem:

All lines are loaded into memory.

Using Generator:


def read_file(filename):
    with open(filename) as file:
        for line in file:
            yield line

Usage:


for line in read_file("data.txt"):
    print(line)

Benefits:

  • Memory efficient
  • Faster processing
  • Handles huge files

2. Employee ID Generator


def employee_ids():
    emp_id = 1000
    while True:
        emp_id += 1
        yield emp_id

Usage:


ids = employee_ids()
print(next(ids))
print(next(ids))
print(next(ids))

Output:

1001
1002
1003

Useful for generating unique IDs.

3. Fibonacci Series


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

Usage:


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

Output:

0
1
1
2
3
5
8
13
21
34

Generators are Iterators

Every generator is automatically an iterator.

Example:


def numbers():
    yield 1
    yield 2

Check:


obj = numbers()
print(iter(obj) == obj)

Output:

True

Generators automatically implement:


__iter__()
__next__()

Advantages of Generators

Advantage Description
Memory Efficient Generates values on demand
Faster for Large Data No need to store everything
Lazy Evaluation Executes only when required
Easy to Create Simpler than custom iterators
Infinite Sequences Can generate endless data

Disadvantages of Generators

Disadvantage Description
Single Use Cannot restart automatically
No Random Access Cannot access values by index
Debugging Difficulty Harder to inspect state
Exhaustion Once consumed, must be recreated

Generators vs Iterators

Feature Generator Iterator
Creation Using yield Using class
Complexity Simple More code
Memory Usage Low Low
iter() Automatic Manual

Example:

Generator:


def numbers():
    yield 1

Iterator:


class Numbers:
    def __iter__(self):
        return self
    def __next__(self):
        pass

Generators are usually easier to implement.

Common Mistakes

1. Using return Instead of yield

Incorrect:


def numbers():
    return 1
    return 2

Correct:


def numbers():
    yield 1
    yield 2

2. Forgetting That Generators Are Single-Use

Incorrect:


gen = numbers()
for x in gen:
    print(x)
for x in gen:
    print(x)

Second loop produces no output.

3. Converting Large Generators to Lists

Incorrect:


list(large_generator)

This defeats the memory-saving benefits.

4. Calling next() Too Many Times

Incorrect:


next(gen)
next(gen)

After exhaustion StopIteration is raised.

5. Using Generators When Random Access Is Needed

Generators do not support:


gen[0]

Use lists if indexing is required.

Best Practices

1. Use Generators for Large Data

Ideal for:

  • Large files
  • Data streams
  • Database records

2. Prefer Generator Expressions

Instead of:


[x*x for x in range(1000000)]

Use:


(x*x for x in range(1000000))

for better memory efficiency.

3. Keep Generator Logic Simple

Avoid overly complex generator functions.

4. Use Meaningful Names

Good:


generate_ids()
read_file()
fibonacci()

Bad:


gen()
func()

5. Handle Exhaustion Properly

Always be aware that generators can only be consumed once.

Conclusion

Python Generators are a powerful feature that enables efficient and memory-friendly data processing. By using the yield keyword, generators produce values one at a time rather than storing entire datasets in memory.

They are ideal for large files, data streams, infinite sequences, and performance-critical applications.

Python Generators – Interview Questions

Q 1: What is a generator in Python?
Ans: A generator is a function that yields values one at a time using yield.
Q 2: How do generators save memory?
Ans: They produce values on demand instead of storing all in memory.
Q 3: Can you loop through a generator?
Ans: Yes, using a for loop or next() function.
Q 4: Can generators be converted to a list?
Ans: Yes, using list(generator).
Q 5: Can a generator be reused?
Ans: No, once exhausted, it cannot be reused.

Python Generators – Objective Questions (MCQs)

Q1. What is a generator in Python?






Q2. Which keyword is used to create a generator in Python?






Q3. What is the main advantage of using a generator over a list?






Q4. What is the output of the following code?

def gen():
for i in range(3):
yield i
g = gen()
print(next(g))
print(next(g))






Q5. Which of the following statements is true about Python generators?






Related Python Tutorials