Comprehensive Breakdown of Python Generators

Comprehensive Breakdown of Python Generators

Here's a simple breakdown of a python generator concept...

It's been a nice ride with Jose Portilla's and Angela Yu's course on python. During this nice study, I came across this beautify concept called Python Generators.

Hey! Calm down because I'm going to explain this concept in a very simple way to understand.

Hmm...Python generators?

This might seem weird to you, but what are we generating? This is just another beautiful concept that builds on what you might have come across as a beginner.

Remember making iterations using a for loop?

"Oh, yeah"...So, let's dive in.

What is a Python Generator?

Python generator are user defined functions that can be used for iteration(an iterator). This allows you to iterate one value at a time. Why is it an iterator? The yield keyword

The yield keyword is the major difference that makes the function an iterator. This yield keyword replaces the return statement in the function block created.

Both yield and return keywords return a value - but the return keyword returns a value and terminates the function while the yield keyword suspends the function then resume whenever it's called by another iterator keyword called next.

The python generator gives a value if called and then waits until another value is called in the program.

Hmm...But what's next?

Relax...It'll be explained as you read through.

Let's have a quick example...

def python_generator(n):
    numbers = []
    for num in range(n):
        numbers.append(num)
    return numbers
print(python_generator(10))

#Output
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

From the example, you can see a list of values created from the iteration. Here's using the return keyword.

Why will I use, the python generator? A major reason is that it makes your program memory efficient.

The list generated has a memory created on the computer but the yield statement won't create the list until it's called. The yield statement can generate the values from the iteration one at a time, still making your program memory efficient

You're going to copy and paste the same code in the previous example and make a slight change. Line 2(empty list) and Line 4 & 5 will be erased.

def python_generator(n):

    for num in range(n):
        yield(num)

print(python_generator(10)) #This will show that an object called python_generator has been created and stored at an address in memory

>>> <generator object python_generator at 0x000002A3F9125510>

What if I need the values generated from the iteration done? Then, use a for loop to see all the values generated.

for n in python_generator(10):
    print(n)

#You can create a list with the generator
print(list(python_generator(10)))

#Output
0
1
2
3
4
5
6
7
8
9

>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Using the "next" and "iter" keywords in the generator

Both keywords are used to generate a sequence of values from the python generator. From the previous example, you created the python generator - let's use both keywords to generate one value at a time.

def python_generator(n):

    for num in range(n):
        yield(num)

gen = python_generator(3) #reducing the argument to three figures
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))

#Output

0
1
2

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-23-38b461427294> in <module>
      8 print(next(gen))
      9 print(next(gen))
---> 10 print(next(gen))

StopIteration:

You can see that there's a generation of all values using the keyword next.

But...There's also a stop iteration warning because there's no other value to be generated. Let's use exception handling(try and except) to report the error to the user.

try:
    def python_generator(n):

        for num in range(n):
            yield(num)

    gen = python_generator(3) #reducing the argument to three figures
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))

except StopIteration:
    print("No more value to be generated")

#Output

0
1
2
No more value to be generated

Since every value is generated one at time in the sequence, you can still work with that value.

def python_generator(n):

    for num in range(n):
        yield(num)

gen = python_generator(3) #reducing the argument to three figures
print(next(gen) + 5) #first value here's 0 (0+5)
print(next(gen) + 5) #second value here's 1 (1+5)
print(next(gen) + 5) #third value here's 2 (2+5)

#Output

5
6
7

Guess that looks more cool to the eyes...Let's move to the next keyword iter

In the next example, the iterable used is a string which won't be written as a function.

name = "Peter Lawson"
for char in name:
    if char == " ":  #this will skip the space between Peter and Lawson in the output(i.e skipping over this iteration)
        continue
    print(char)

#Output

P
e
t
e
r
L
a
w
s
o
n

Let's try using the keyword next...

print(next(name))

#Output

TypeError                                 Traceback (most recent call last)
<ipython-input-34-e60a7ac20bfa> in <module>
----> 1 print(next(name))

TypeError: 'str' object is not an iterator

An error pops out notifying that the string is not an iterator...Here's the syntax to counter this error below using iter, then the keyword next can be used to generate the sequence.

name_iter = iter(name)
print(next(name_iter))
print(next(name_iter))
print(next(name_iter))

#Output

name_iter = iter(name)

print(next(name_iter))
print(next(name_iter))
print(next(name_iter))

P
e
t

You can go on to complete the iteration by using the next keyword to generate the values.

Conclusion

Python generators can be used to generate a sequence of values based on the keywords explained in the article - next and iter. The syntax in using these keywords has been explained in the article.

Also, the yield keyword in the code makes your program readable and easier to understand to others.

When next you're working on iterations and you consider memory efficiency or a big data - consider using the interesting concept of generators.