Differentiate Functions and Generators
In this step, you will learn the key differences between regular Python functions and generators. Understanding this distinction is crucial for writing efficient and memory-friendly code, especially when dealing with large datasets or infinite sequences.
Functions:
A function is a block of code that performs a specific task. When a function is called, it executes its code, potentially performs calculations, and returns a value (or None
if no explicit return
statement is present). The function's state is not preserved between calls.
Generators:
A generator is a special type of function that uses the yield
keyword instead of return
. When a generator is called, it returns an iterator object. Each time you request a value from the iterator, the generator executes until it encounters a yield
statement. The generator then pauses, saves its state, and yields the value. The next time a value is requested, the generator resumes from where it left off.
Let's illustrate this with an example. First, create a file named function_vs_generator.py
in your ~/project
directory using the VS Code editor.
## ~/project/function_vs_generator.py
## Regular function
def square_numbers_function(numbers):
result = []
for number in numbers:
result.append(number * number)
return result
## Generator function
def square_numbers_generator(numbers):
for number in numbers:
yield number * number
## Example usage
numbers = [1, 2, 3, 4, 5]
## Using the function
function_result = square_numbers_function(numbers)
print("Function Result:", function_result)
## Using the generator
generator_result = square_numbers_generator(numbers)
print("Generator Result:", list(generator_result)) ## Convert generator to list for printing
Now, execute the Python script:
python ~/project/function_vs_generator.py
You should see the following output:
Function Result: [1, 4, 9, 16, 25]
Generator Result: [1, 4, 9, 16, 25]
Both the function and the generator produce the same result. However, the key difference lies in how they achieve this. The function calculates all the squares and stores them in a list before returning. The generator, on the other hand, yields each square one at a time, only when it's requested.
To further illustrate the difference, let's modify the script to print the type of the returned object:
## ~/project/function_vs_generator.py
## Regular function
def square_numbers_function(numbers):
result = []
for number in numbers:
result.append(number * number)
return result
## Generator function
def square_numbers_generator(numbers):
for number in numbers:
yield number * number
## Example usage
numbers = [1, 2, 3, 4, 5]
## Using the function
function_result = square_numbers_function(numbers)
print("Function Result Type:", type(function_result))
## Using the generator
generator_result = square_numbers_generator(numbers)
print("Generator Result Type:", type(generator_result))
Execute the script again:
python ~/project/function_vs_generator.py
The output will be:
Function Result Type: <class 'list'>
Generator Result Type: <class 'generator'>
This clearly shows that the function returns a list
, while the generator returns a generator
object. Generators are memory-efficient because they don't store all the values in memory at once. They generate values on demand.