The difference between Python iterable objects, iterators, generators

This article briefly talks about the relationship between iterable objects, iterators and generators.



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.


2)next()

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:



Question: The iter function appears in the above example, what is this? Does it have something to do with the __iter__ method?
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


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325441497&siteId=291194637