An iterator is an object that implements the iteration protocol, which consists of two methods: __iter__() and __next__().  The __iter__() method is called when an iterator object is initialized.The __next__() method is called to retrieve the next item from the iterator.

The StopIteration exception is raised when the __next__() method of an iterator object is called  but there are no items to iterate over. This exception is used to signal  the end of iteration.

L = ["Pynerds", "Python", "Django"]

#Create a list iterator object
I = iter(L)

print(next(I))
print(next(I))
print(next(I))
print(next(I))

The builtin next() function is used to retrieve the next item from an iterator object. It actually calls the __next__() method of the iterator object. 

#Define a generator function
def func():
   L = [0, 1, 2, 3]
   for i in L:
       yield i

gen = func()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))

Handling StopIteration exceptions

The most obvious way to handle a StopIteration exception is to use a for loop.  The for loop allows you to iterate over the sequence until a StopIteration exception is raised. The loop handles the exception automatically for you. 

my_sequence = [1, 2, 3, 4, 5]

my_iter = iter(my_sequence)

for i in my_iter:
    print(i)

You can also use the try-except blocks to handle the exception explicitly.

my_list = ["Pynerds", "Python", "Django"]

#Create a list iterator object
my_iter = iter(my_list)

try:
   print(next(my_iter))
   print(next(my_iter))
   print(next(my_iter))
   print(next(my_iter))

except StopIteration:
    print("The iterator is exhausted.")

When using while loop:

def func():
   L = [0, 1, 2, 3]
   for i in L:
       yield i

gen = func()

try:
    while True:
        print(next(gen))
except StopIteration:
    print("The iterator is exhausted.")