Iterators are used in almost all languages in the form of built-in functions that can return an object or an element in a sequential or a defined way. The most common example of an iterator is the for loop which can iterate over a set of commands or an array/list containing multiple elements. The iterator can be defined as an object to be used in custom fields. The iterator object in Python must be called using the iterator protocol which includes __iter__() and __next__() functions. An iterator object can be used over any container/data type which is iterable or contains multiple values or changing values. 

Here is a simple implementation of an iterator in Python.

l1 = ["item1", "item2", "item3"] #This is a defined list/container which contains the iterables

i1 = iter(l1) #We have defined the iterator in a separate variable so that it can be called

print(i1.__next__()) #The obj.__next__() function will act as the pusher for the iterator, the next function tells the iterator obj to move on the next one.
print(i1.__next__())
print(i1.__next__())

#If we print one more iterable from the list, it will give us an error that there are no iterables.

We can also use the methods inside a class in an OOP fashion, this allows for more control and to make custom iterators that we can use all over the code:

class m1: #This is a iterator class for a simple counter which is infinite

   def __iter__(self): #This is the iteration class which iterates over a variable
       self.a = 1
       return self #This returns the self within the class

   def __next__(self): #This class moves the iterator over to the other value
       a = self.a
       self.a += 1
       return a

call2 = iter(m1()) #We have directly called the class as an object

print(next(call2)) #Everytime we print the next function with the class object, it will iterate a single addition to the original value
print(next(call2)) 
print(call2.__next__()) #We can also use the obj.__next__() function
print(next(call2))
print(next(call2))


We can also use a for loop with the class object, to have it run infinitely:

class m1: #This is a iterator class for a simple counter which is infinite

   def __iter__(self): #This is the iteration function which iterates over a variable
       self.a = 1
       return self #This returns the self within the class

   def __next__(self): #This class moves the iterator over to the other value
       a = self.a
       self.a += 1
       return a

call2 = iter(m1()) #We have directly called the class as an object

print(next(call2)) #Everytime we print the next function with the class object, it will iterate a single addition to the original value
print(next(call2))
print(next(call2))
print(next(call2))
print(next(call2))

for i in call2: #This for loop is also an iterator but it works on the custom iterator
   print(next(call2))

Python Generator:

In a similar fashion to iterators we also have generators in Pythons, these generators methods/functions are very similar to general and original iter() and next() class functions but they utilise a yield statement instead of a return statement. 

The return statement will completely terminate a function and a yield statement will save the last value from the called function and continue from that value the next time that function is called, a generator function can contain more than one yield statement. Lets see how it works:

def gen1():

   a = 75
   print("First: ")
   yield a #The yield statement will save the value from the first call and iterate the next whenever the function is called again
   a = 95
   print("First: ")
   yield a #This will yield 95 in "a", if the function is called a second time
   a = 105
   print("First: ")
   yield a

p = gen1()
print(next(p))
print(next(p))
print(next(p))

We can also use generators in a bid to cut out the requirement of raising exceptions, let’s check out an example to list the separate characters in a string:

def mystr(mstr):

   length = len(mstr)
   for i in range(0, length):
       yield mstr[i] #This will yield each character in the string one by one


for i in mystr("Python"): #We have used a loop to call the function again and again and it saves the last and calls it again, if we replace the yield statement with return, it will print "P" just once
   print(i)

Categorized in: