Generator functions are functions in Python that provide an easy way to perform iterations. This is useful because working with lists requires that we store each value in memory, which isn’t practical for large input. Further, building an iterator from scratch requires a great deal of code, compared to the simple implementation of generators. For example, when building an iterator class, you need to define dunder methods ‘iter()’ and ‘next()’, keep track of internal states, and raise a ‘StopIteration’ when there are no additional values to return. To demonstrate the power of generator functions we will compare different implementations of a function used to generate positive integers from 0 to n.
Let’s get started!
First, let’s define a function that takes an integer as input and returns a list of positive even integers less than or equal to the input:
def generate_list(input_value):
number, numbers = 0, []
while number <= input_value:
numbers.append(number)
number += 2
return numbers
Now, let’s use our function to define a list of positive integers from 0 to n= 10:
values = generate_list(10)

We can perform a sum on the resulting list using the built-in sum method:
print("Sum of list: ", sum(values))

The issue here is that the full list is built in memory. This become problematic when you are dealing with a large amount of data. We can employ the generator pattern to amend this issue.
To proceed, let’s implement a generator as an iterator object. Our class will need dunder methods ‘init()’, ‘iter()’, and ‘next()’. We also needs to raise a ‘StopIteration’ when there are no additional values to return. Let’s first define our ‘init()’ method:
class iterator_object(object):
def __init__(self, input_value):
self.input_value = input_value
self.numbers = 0
In our ‘init()’ method we initialize the class attributes. Next, let’s define the dunder method ‘iter()’:
class iterator_object(object):
...
def __iter__(self):
return self
Now, let’s add our ‘next()’ method:
class iterator_object(object):
...
def __next__(self):
return self.next()
Finally, we can define the class method ‘next()’:
class iterator_object(object):
...
def next(self):
if self.number <= self.input_value:
current, self.number = self.number, self.number + 2
return current
else:
raise StopIteration()
Now we can define an instance of our class with an input value of 10 and print out the sum of the resulting iterator object:
value = iterator_object(10)
print("Sum using an Iterator Object: ", sum(value))

Which is the result we expect. Notice in order to implement our generator as an iterator object we needed to write quite a bit of code:
class iterator_object(object):
def __init__(self, input_value):
self.input_value = input_value
self.number = 0
def __iter__(self):
return self
def __next__(self):
return self.next()
def next(self):
if self.number <= self.input_value:
current, self.number = self.number, self.number + 2
return current
else:
raise StopIteration()
Luckily, python provides the ‘yield’ keyword, which when used provides a shortcut to building iterators. We can define the same function using ‘yield’:
def generator_function(input_value):
number = 0
while number <= input_value:
yield number
number += 2
Let’s call our generator with an input value of ten and print the sum of the result:
value = generator_function(10)
print("Sum using a Generator: ", sum(value))

As we can see we accomplished the same result with significantly less code than the iterator object implementation, while keeping the benefits of iterators. I’ll stop here but feel free to play around with the code yourself.
CONCLUSIONS
To summarize, in this post we discussed generator functions in python. We outlined three implementations of the same function to demonstrate the power of generator functions. We discussed how performing some operations on lists becomes problematic for large input. We resolved this issue by building an iterator object implementation of a generator function. This solution required a good deal of code. Finally, we discussed the use of the ‘yield’ statement to define generator functions which provides a shortcut to building iterators. I hope you found this post interest/useful. The code in this post is available on GitHub. Thank you for reading!