Introduction
A Generator Function is a special type of function that uses the yield keyword instead of return to produce values one at a time.
Unlike normal functions that return all results at once and then terminate, generator functions pause execution after each yield and resume when the next value is requested.
Generator functions are widely used in:
-
Large Data Processing
-
File Handling
-
Log Analysis
-
API Pagination
-
Data Streaming
-
Automation Frameworks
-
Memory-Efficient Applications
In this tutorial, you will learn what generator functions are, how they work, practical examples, automation testing use cases, common mistakes, and best practices.
What is a Generator Function?
A generator function is a function that contains one or more yield statements.
When called, it does not execute immediately. Instead, it returns a generator object that can generate values one by one.
Syntax
def generator_function():
yield value
Why Use Generator Functions?
Generator functions help:
-
Save memory
-
Process large datasets efficiently
-
Generate values on demand
-
Improve performance
-
Support lazy evaluation
Normal Function vs Generator Function
Normal Function
def numbers():
return [1, 2, 3]
print(numbers())
Output
[1, 2, 3]
Returns all values at once.
Generator Function
def numbers():
yield 1
yield 2
yield 3
print(numbers())
Output
<generator object numbers at 0x...>
Returns a generator object.
Basic Generator Function Example
Example
def numbers():
yield 1
yield 2
yield 3
for number in numbers():
print(number)
Output
1
2
3
Values are generated one at a time.
Understanding How Generators Work
Example
def demo():
print("Start")
yield 1
print("Middle")
yield 2
print("End")
yield 3
generator = demo()
print(next(generator))
print(next(generator))
print(next(generator))
Output
Start
1
Middle
2
End
3
The function pauses at each yield.
Using next() with Generators
Example
def count():
yield 10
yield 20
yield 30
generator = count()
print(next(generator))
print(next(generator))
print(next(generator))
Output
10
20
30
next() retrieves the next generated value.
Generator Function with Loop
Example
def generate_numbers():
for i in range(5):
yield i
for number in generate_numbers():
print(number)
Output
0
1
2
3
4
Generator Function with Conditions
Example
def even_numbers(limit):
for num in range(limit):
if num % 2 == 0:
yield num
for number in even_numbers(10):
print(number)
Output
0
2
4
6
8
Generator Function Returning Squares
Example
def squares(limit):
for num in range(limit):
yield num ** 2
for value in squares(5):
print(value)
Output
0
1
4
9
16
Infinite Generator Function
Example
def infinite_counter():
number = 1
while True:
yield number
number += 1
generator = infinite_counter()
print(next(generator))
print(next(generator))
print(next(generator))
Output
1
2
3
Generators can produce unlimited values.
Memory Efficiency of Generators
Using List
numbers = [x for x in range(1000000)]
Creates all values in memory.
Using Generator
numbers = (
x for x in range(1000000)
)
Generates values only when needed.
This saves memory.
Generator Function Reading Files
Example
def read_file(file_name):
with open(file_name) as file:
for line in file:
yield line
for line in read_file("data.txt"):
print(line)
Only one line is loaded at a time.
Generator Function Processing Logs
Example
def log_reader():
logs = [
"INFO",
"WARNING",
"ERROR"
]
for log in logs:
yield log
for entry in log_reader():
print(entry)
Output
INFO
WARNING
ERROR
Generator Function for API Pagination
Example
def api_pages():
yield "Page 1"
yield "Page 2"
yield "Page 3"
for page in api_pages():
print(page)
Output
Page 1
Page 2
Page 3
Useful when APIs return paginated data.
yield from in Generator Functions
Used to delegate iteration to another generator.
Example
def numbers():
yield 1
yield 2
def values():
yield from numbers()
yield 3
for item in values():
print(item)
Output
1
2
3
Generator Functions in Selenium Automation
Example
Generate multiple test users.
def test_users():
yield "admin"
yield "manager"
yield "tester"
for user in test_users():
print(user)
Output
admin
manager
tester
Useful for data-driven testing.
Generator Functions in API Automation
Example
def status_codes():
yield 200
yield 201
yield 404
for code in status_codes():
print(code)
Output
200
201
404
Useful for validating multiple responses.
StopIteration Exception
When a generator has no more values, Python raises StopIteration.
Example
def numbers():
yield 1
generator = numbers()
print(next(generator))
print(next(generator))
Output
1
StopIteration
Common Mistakes Beginners Make
Using return Instead of yield
Incorrect
def numbers():
return 1
return 2
Only the first return executes.
Correct
def numbers():
yield 1
yield 2
Forgetting to Iterate
Incorrect
generator = numbers()
Produces no output.
Correct
for value in generator:
print(value)
Calling next() Excessively
Example
generator = numbers()
next(generator)
next(generator)
next(generator)
May raise:
StopIteration
Expecting a List
Example
print(numbers())
Output
<generator object ...>
Convert if necessary:
list(numbers())
Best Practices
Use Generators for Large Data
Ideal for:
-
Files
-
Logs
-
Database Records
-
API Responses
Keep Generator Functions Focused
One generator should handle one responsibility.
Use Meaningful Names
Examples:
read_logs()
generate_users()
fetch_pages()
Use yield from for Nested Generators
yield from another_generator()
Improves readability.
Prefer Loops Over Repeated next()
Safer and cleaner.
Advantages of Generator Functions
-
Memory efficient
-
Faster for large datasets
-
Lazy evaluation
-
Cleaner code
-
Better performance
Limitations of Generator Functions
-
Values can be consumed only once
-
No random access
-
Slightly harder to debug
Generator Function vs Normal Function
| Feature | Generator Function | Normal Function |
|---|---|---|
| Uses yield | Yes | No |
| Uses return | Optional | Yes |
| Returns Generator Object | Yes | No |
| Memory Efficient | Yes | No |
| Lazy Evaluation | Yes | No |
| Produces Values One by One | Yes | No |
Conclusion
Generator functions are one of Python’s most powerful features for creating memory-efficient and scalable applications. By using the yield keyword, they generate values on demand rather than storing everything in memory.
Whether you’re processing large files, handling API pagination, streaming data, or building Selenium automation frameworks, generator functions can significantly improve performance and reduce memory usage.
Mastering generator functions is an important step toward advanced Python programming and writing production-ready applications.
Frequently Asked Questions (FAQs)
What is a generator function?
A generator function is a function that uses yield to generate values one at a time.
What does a generator function return?
It returns a generator object.
gen = my_generator()
How is a generator different from a normal function?
A normal function returns all results at once, while a generator produces values one at a time.
Why are generators memory efficient?
Because they generate values only when needed instead of storing all values in memory.
What is yield from?
It delegates iteration to another generator.
yield from another_generator()
Key Takeaways
-
Generator functions use the
yieldkeyword. -
They return generator objects.
-
Values are generated one at a time.
-
Generators support lazy evaluation.
-
They are memory efficient.
-
next()retrieves the next generated value. -
yield fromdelegates to another generator. -
Useful for large files, logs, and API pagination.
-
Commonly used in Selenium and API automation frameworks.
-
Generator functions help build scalable and high-performance Python applications.
