Iterable Objects and Iterators
_Iterative objects are not necessarily iterators, but iterators are always iterative objects. In Python, list sequence types, etc., we can traverse the data by for...in. We call it Iterable. The iterator must also implement _next_() as long as it implements _iter_() or _getitem_().
from collections.abc import Iterable, Iterator my_list = [1, 2, 3] my_itorlist = iter(my_list) print(isinstance(my_list, Iterator)) print(isinstance(my_itorlist, Iterator)) pass
We can see that list is not an iterator type. The iter() function can turn an iterator object into an iterator object.
_After transforming an iterative object into an iterator object, we can access elements sequentially through next(). The following figure shows the transformation of iteratable objects to iterators and the method of accessing elements. After accessing all elements, a StopIteration exception is thrown.
my_list = [1,2,3] my_itorlist = iter(my_list) print(next(my_itorlist)) print(next(my_itorlist)) print(next(my_itorlist)) print(next(my_itorlist))
Why do we need iterators?
Fibonacci sequence refers to such a sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34. When we encounter the problem that Fibonacci sequence needs to print the first 100 digits, the most common solution is to use the following while loop.
def fib(index): re_list = [] n,a,b = 0,0,1 while n<index: re_list.append(b) a,b = b, a+b n += 1 return re_list
It is undeniable that this is a better solution, but in the face of printing a large number of Fibonacci sequences, we will face a problem of greatly increasing memory overhead. It's impossible for us to store all 10 million data in a list. The advantages of the iterator are demonstrated. The iterator returns only the next number, and does not record a single data. It calculates when we need to print. Using iterators to solve the Fibolacci sequence problem, we can face a large amount of data without worrying about memory usage.
class Fb: def __init__(self, n): self.n = n #Number of prints self.current = 0 self.a = 0 self.b = 1 def __next__(self): if self.current < self.n: """ a=b b=a+b """ self.a, self.b = self.b, self.a + self.b self.current += 1 return self.a else: raise StopIteration def __iter__(self): return self if __name__ == '__main__': fib_print = Fb(1000) for num in fib_print: print(num)
Custom Iterator
By customizing an iterator, we can better understand what an iterator is.
from collections.abc import Iterator#Abstract base classes for importing iterators class Company(object): def __init__(self, employee_list): self.employee = employee_list def __iter__(self): return LevyIterator(self.employee) class LevyIterator(Iterator):#Custom Iterator def __init__(self,employee_list): self.iter_employee = employee_list self.index = 0 def __next__(self): try: next_obj = self.iter_employee[self.index] except IndexError:#Capture Index exceptions raise StopIteration#Abnormal StopIteration throwing an iterator self.index +=1 return next_obj if __name__ == "__main__": company = Company(["tom", "bob", "jane"]) my_itor = iter(company) #To become an iterator object while True: try: print (next(my_itor)) except StopIteration: break # for item in company: # print(item)
In the above code, while.. break code in main is the part of our iteration output, which is the essence of for.. in output: first, the object is transformed into an iterator type through obj. ITER (), and then the element is output through continuous next(obj).