Python 3x Pandas Django

Python Generators


The generator is a very important key term and advanced topic in python. The generator allows us to generate a sequence of values over time. What is that mean? you see we actually learned generator. do you remember the range()?. The range is a type of generator but what is that? a generator is a special type of thing in python that allows us to create our own iterator functions and use special keyword yield and it can pause and resume functions.

Generators are more memory efficient than the iterator. elements are generated dynamically and the next item is generated only after the first is consumed

let's start with a simple example,

def mygenerator():
    yield 'ItemA'    #Stop & Resume
    yield 'ItemB'    #Stop & Resume
    yield 'ItemC'    #Stop & Resume

gen_obj1 = mygenerator()

print(next(gen_obj1))

Output:

ItemA

Now, execute these statements two more times and you will see ItemB & ItemC

Output:

print(next(gen_obj1))   #Output: ItemB
print(next(gen_obj1))   #Output: ItemC

In the above example, the mygenerator() function is a generator function. It uses yield instead of return keyword. So, this will return the value against the yield keyword each time when we call the iterator next().

Yield vs Return

The difference between yield and return is that yield returns a value and pauses the execution while maintaining the internal states, whereas the return statement returns a value and terminates the execution of the function.

The function finally terminates when next() encounters the StopIteration error

print(next(gen_obj1))   #Error:     StopIteration

Using for Loop with Generator

Example 1:

def get_sequence_upto(num):
  for item in range(1,num):
        yield item    #Stop and Resume on each time

gen_obj1 = get_sequence_upto(10)

print(next(gen_obj1))       #Output: 1
print(next(gen_obj1))       #Output: 2
print(next(gen_obj1))       #Output: 3
print(next(gen_obj1))       #Output: 4
print(next(gen_obj1))       #Output: 5
print(next(gen_obj1))       #Output: 6
print(next(gen_obj1))       #Output: 7
print(next(gen_obj1))       #Output: 8
print(next(gen_obj1))       #Output: 9

Now, execute this statements again, you will get an StopIteration Error as range() stops the sequence with 9.

Example 2:

def get_odd_only(num):
  for item in range(1,num):
      if (item % 2) != 0:
          yield item    #Stop and Resume on each time

gen_obj1 = get_odd_only(10)

print(next(gen_obj1))       #Output: 1
print(next(gen_obj1))       #Output: 3
print(next(gen_obj1))       #Output: 5
print(next(gen_obj1))       #Output: 7
print(next(gen_obj1))       #Output: 9

# Stop the iteration on next call
print(next(gen_obj1))       #Error: StopIteration

Try..Except block for StopIteration error

Example 1:

def get_odd_only(num):
  for item in range(1,num):
      if (item % 2) != 0:
          yield item    #Stop and Resume on each time

gen_obj1 = get_odd_only(10)

#Try.. Except Block
while True:
    try:
        print ("Received on next(): ", next(gen_obj1))
    except StopIteration:
        break

Output:

Received on next():  1
Received on next():  3
Received on next():  5
Received on next():  7
Received on next():  9

In the above example, used the try..except block to handle the StopIteration error. It will break the while loop once it catches the StopIteration error.

We can use for loop to traverse the elements over the generator. In this case the next() function is called implicitly and the StopIteration is also automatically taken care of.

Generator with For Loop:

Example 1:

def get_odd_only(num):
  for item in range(1,num):
      if (item % 2) != 0:
          yield item    #Stop and Resume on each time

gen_obj1 = get_odd_only(10)

for item in gen_obj1:
    print(item)

Output:
1
3
5
7
9

Generator Expression

Python also provides a generator expression, which is a shorter way of defining simple generator functions. The generator expression is an anonymous generator function.

Let's take above examples from try.. except block and convert them to expression.

Example 1:

get_odd_only = (x for x in range(10) if x % 2 != 0)

#Try.. Except Block
while True:
    try:
        print ("Received on next(): ", next(get_odd_only))
    except StopIteration:
        break

Output:

Received on next():  1
Received on next():  3
Received on next():  5
Received on next():  7
Received on next():  9

In the above example, (x for x in range(10) if x % 2 != 0) is a generator expression.

The first part of an expression x is the yield value and the second part is the for loop and if condition. for x in range(10) if x % 2 != 0

Wihtout if condition:

Example 2:

get_odd_only = (x for x in range(1,10,2))

#Try.. Except Block
while True:
    try:
        print ("Received on next(): ", next(get_odd_only))
    except StopIteration:
        break

Output:

Received on next():  1
Received on next():  3
Received on next():  5
Received on next():  7
Received on next():  9

If you have any doubts or queries related to this chapter, get them clarified from our Python Team experts on ibmmainframer Community!