A brief relationship diagram of the three
Iterables and Iterators
At first I thought the two were equivalent, but then I found out that they are not; here is the straight-forward conclusion:
1) Iterable objects contain iterators.2) If an object has an __iter__ method, it is an iterable object; if an object has a next method, it is an iterator.
3) To define an iterable object, you must implement the __iter__ method; to define an iterator, you must implement the __iter__ and next methods.
You may ask, is conclusion 3 contradicting conclusion 2? Since an object with a next method is an iterator, why does an iterator have to implement two methods at the same time?
Because of conclusion 1, iterators are also iterable objects, so iterators must also implement the __iter__ method.Introduce the two methods involved above:
1) __ process __ ()
This method returns an instance of the iterator class for the current object . Because both iterable objects and iterators implement this method, there are two ways to write them.
Writing method 1: The writing method for the iterable object class returns an instance of the iterator class of the iterable object.
Writing method 2: The writing method used for the iterator class directly returns self (that is, itself), indicating that itself is its own iterator.
Maybe a little dizzy, it doesn't matter, the following will give an example of the two writing methods, we will look at the specific example.
Returns each step of the iteration. When implementing this method, pay attention to throwing a StopIteration exception when the boundary is exceeded at the end.
Here is an example of iterable objects and iterators:
#!/usr/bin/env python # coding=utf-8 class MyList(object): # Define the iterable object class def __init__(self, num): self.data = num # upper bound def __iter__(self): return MyListIterator(self.data) # Returns an instance of the iterator class of the iterable object class MyListIterator(object): # Define the iterator class, which is the iterator class of the MyList iterable object def __init__(self, data): self.data = data # upper bound self.now = 0 # The current iteration value, the initial value is 0 def __iter__(self): return self # Returns an instance of the object's iterator class; because it is an iterator, return self def next(self): # The method that the iterator class must implement while self.now < self.data: self.now += 1 return self.now - 1 # return the current iteration value raise StopIteration # exceeds the upper bound and throws an exception my_list = MyList(5) # get an iterable object print type(my_list) # return the type of the object my_list_iter = iter(my_list) # Get the iterator instance of the object, the iter function will be explained in detail below print type(my_list_iter) for i in my_list: # 迭代 print i
operation result:
In fact, this function is closely related to iteration. By printing "help(iter)" on the Python command line, we know that it has the following two usages.
Usage 1: iter(callable, sentinel)
keeps calling callable until its return value is equal to sentinel. The callable can be a function, method or an instance that implements the __call__ method.
Usage 2: iter(collection)
1) It is used to return the iterator instance of the collection object. I think the collection here represents an iterable object, that is, the object must implement the __iter__ method; in fact, the iter function and the __iter__ method It is very closely related. iter() directly calls the __iter__() of the object, and uses the return result of __iter__() as its own return value, so this usage is often called "creating an iterator".
2) The iter function can be called explicitly, or when "for i in obj:" is executed, the Python interpreter will automatically call iter(obj) at the first iteration, and the next iteration will call the iterator's next method, and the for statement will Automatically handle the last StopIteration exception thrown.
Through the above example, I believe that I have a more specific understanding of iterable objects and iterators, so what is the relationship between generators and them? Let's talk briefly
Builder
The generator is a special kind of iterator. The generator automatically implements the "iterator protocol" (ie __iter__ and the next method) , so there is no need to manually implement the two methods.
The generator can change the current iteration value in the process of iteration, while modifying the current iteration value of the ordinary iterator will often cause an exception and affect the execution of the program.
See an example of a generator:
#!/usr/bin/env python # coding=utf-8 def myList(num): # define the generator now = 0 # current iteration value, initially 0 while now < num: val = (yield now) # Returns the current iteration value and accepts possible send values; yield is explained below now = now + 1 if val is None else val # val is None, the iteration value is incremented by 1, otherwise the current iteration value is reset to val my_list = myList(5) # get a generator object print my_list.next() # Returns the current iteration value print my_list.next() my_list.send(3) # reset the current iteration value print my_list.next() print dir(my_list) # Return the method name owned by the object, you can see that __iter__ and next are in it
operation result:
Functions with the yield keyword are all generators, and yield can be understood as return, which returns the following value to the caller. The difference is that after return returns, the function will be released, while the generator will not. When the next method is called directly or the for statement is used for the next iteration, the generator will execute from the next sentence of yield until it encounters the next yield.
References:
Python Core Programming Second Edition Sections 11.10, 13.13.3
Complete understanding of Python iterative objects, iterators, generators
Deep dive into iterators and generators in Python
How to better understand Python iterators and generators
If there is any inappropriate place in the text, I hope to accommodate and point out, thank you