Generators In Python | Generator Functions with Examples

The concept of iterators is slightly lengthy. This is because, to implement an iterator, we need to implement the __iter__() and __next__() classes, then keep a track of the internal states & finally raise a StopIteration. This lengthy process can be minimized with the use of generators in Python.

Generators in Python are a simple way to create iterator functions. In simple, the generator is a function that yields an object (iterator) which we can iterate over one value at a time. Let us now see how to create one such function.

How to create generators in Python?

A normal function with a yield statement instead of a return statement is called a generator function. Both yield and return statements are used to return some value from a function. The difference between them is that a return statement terminates the execution of a function entirely and returns the value to the user, whereas a yield statement pauses the function saving all its current states and immediately returns a value to the user, but later continues from it left off.

Generators in Python Examples

1) A simple generator function that yields the first three numbers. 

# generator function which yields the first three numbers
def FirstThree():
    yield 1
    yield 2
    yield 3
# main function to print the values
for res in FirstThree():
    print (res, end = ' ')
Output:
1 2 3

2) We can also create a generator object for the generator function using which the values of the generator function can be accessed as shown below.

# generator function which yields the first three numbers
def FirstThree():
yield 1
yield 2
yield 3

# main function to print the values
numbers = FirstThree()
print(next(numbers))
print(next(numbers))
print(next(numbers))
Output:
1
2
3

3) In the above example, instead of writing three print statements, we can use the for loop as shown below.

# generator function which yields the first three numbers
def FirstThree():
yield 1
yield 2
yield 3

# main function to print the values
numbers = FirstThree()
for res in numbers:
print (res, end = ' ')
Output:
1 2 3

In the above code, numbers is the object created for the generator function to access the values

Why are generators useful?

There are several advantages of using generators in Python. Some of them are:

a) They are easy to implement

Here is an example using iterators to print first 3 numbers starting from 1 i.e 1, 2, 3.

class FirstThree:
    def __iter__(obj):
        obj.num = 1
        return obj
    def __next__(obj):
        if(obj.num <= 3):
            val = obj.num
            obj.num += 1
            return val
        else:
            raise StopIteration
numbers = FirstThree()
for res in numbers:
    print (res, end = ' ')

The same program can be implemented and executed using generators in a much simpler way. Have a quick look at the code using generators to implement the same program.

# generator function which yields the first three numbers
def FirstThree():
    yield 1
    yield 2
    yield 3
# main function to print the values
for res in FirstThree():
    print (res, end = ' ')

b) They are memory efficient

A normal function, when used in an iterator, will create the entire sequence in memory before returning it as a result. This consumes a lot of memory if in case the number of items in the sequence are large. Where as in case of generator functions, the sequence is memory friendly and it only produces one item at a time.