The essence of iter() function and next() function for...in... Loop

Keywords: Python

Links to the original text: https://blog.csdn.net/weixin_43867210/article/details/85628221

Iteration is a way of accessing set elements. Iterator is an object that can remember the location of traversal. Iterator objects are accessed from the first element of the collection until all elements are accessed. Iterators can only move forward and not backward.

1. Iterable Objects

We already know that we can use for for list, tuple, str and other types of data. in... We call this process traversal, or iteration.

>>> for i in 100:
...     print(i)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
# Int integers are not iterable, that is, int integers are not Iterable

# We customize a container called MyList to store data, which can be added through the add method.
>>> class MyList(object):
...     def __init__(self):
...             self.container = []
...     def add(self, item):
...             self.container.append(item)
...
>>> mylist = MyList()
>>> mylist.add(1)
>>> mylist.add(2)
>>> mylist.add(3)
>>> for num in mylist:
...     print(num)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'MyList' object is not iterable
>>>
# MyList container objects are also not iterative

We customize a container type MyList, where we place a MyList object that holds multiple data in for... In... In the statement of ______, find for ______. In... We can't take one piece of data from it and return it to us in turn. That is to say, we arbitrarily encapsulate a type that can store more than one piece of data, but it can't be used iteratively.

We will be able to adopt for ___________. in... This kind of statement iteratively reads an object of data for our use and is called Iterable **.

2. How to judge whether an object can be iterated

You can use isinstance() to determine whether an object is an Iterable object:

In [50]: from collections import Iterable

In [51]: isinstance([], Iterable)
Out[51]: True

In [52]: isinstance({}, Iterable)
Out[52]: True

In [53]: isinstance('abc', Iterable)
Out[53]: True

In [54]: isinstance(mylist, Iterable)
Out[54]: False

In [55]: isinstance(100, Iterable)
Out[55]: False

3. Essence of Iterable Objects

We analyze the process of using iteratively the iteratable object and find that every iteration (i. E. for _ In... Each iteration) returns the next data in the object and reads it backwards until all data is iterated over. So, in this process, there should be a "person" to record the number of data accessed each time, so that each iteration can return the next data. We call this "human" who can help us iterate data an Iterator.

The essence of an iterative object is to provide us with an intermediate "human" that is, an iterator to help us iterate through it.

Iterable objects provide us with an iterator through the _iter_ method. When we iterate over an iterative object, we actually get an iterator provided by the object first, and then use this iterator to obtain each data in the object in turn.

That is to say, an object with _iter_ method is an iterative object.

>>> class MyList(object):
...     def __init__(self):
...             self.container = []
...     def add(self, item):
...             self.container.append(item)
...     def __iter__(self):
...             """Returns an iterator"""
...             # For the moment, we ignore how to construct an iterator object.
...             pass
...
>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True
>>>
# This test found that the mylist object with the _iter_ method was already an iterative object.

4. iter() function and next() function

list, tuple, etc. are iteratable objects. We can get iterators of these iteratable objects by iter() function. Then we can use the next() function continuously to get the next data for the acquired iterator. The iter() function actually calls the _iter_ method of an iteratable object.

>>> li = [11, 22, 33, 44, 55]
>>> li_iter = iter(li)
>>> next(li_iter)
11
>>> next(li_iter)
22
>>> next(li_iter)
33
>>> next(li_iter)
44
>>> next(li_iter)
55
>>> next(li_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

Note that when we have iterated over the last data, calling the next() function again throws an exception to StopIteration to tell us that all data has been iterated and that the next() function is no longer needed.

5. How to judge whether an object is an iterator

You can use isinstance() to determine whether an object is an Iterator object:

In [56]: from collections import Iterator

In [57]: isinstance([], Iterator)
Out[57]: False

In [58]: isinstance(iter([]), Iterator)
Out[58]: True

In [59]: isinstance(iter("abc"), Iterator)
Out[59]: True

* 6. Iterator

From the above analysis, we know that the iterator is used to help us record the location visited by each iteration. When we use the next() function for the iterator, the iterator will return to us the data of the next location at which it records. In fact, when you use the next() function, you call the _next_ method of the iterator object (python 3 is the _next_ method of the object, and python 2 is the next() method of the object). So, if we want to construct an iterator, we need to implement its _next_ method. But that's not enough. python requires that the iterator itself be iterative, so we also need to implement the _iter_ method for the iterator, and the _iter_ method returns an iterator. The iterator itself is an iterator, so the _iter_ method of the iterator can return itself.

An object that implements the _iter_ method and _next_ method is an iterator.

class MyList(object):
    """A Customized Iterable Object"""
    def __init__(self):
        self.items = []

    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        myiterator = MyIterator(self)
        return myiterator


class MyIterator(object):
    """A custom iterator for the above iteratable objects"""
    def __init__(self, mylist):
        self.mylist = mylist
        # Currt is used to record the location current ly accessed
        self.current = 0

    def __next__(self):
        if self.current < len(self.mylist.items):
            item = self.mylist.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self


if __name__ == '__main__':
    mylist = MyList()
    mylist.add(1)
    mylist.add(2)
    mylist.add(3)
    mylist.add(4)
    mylist.add(5)
    for num in mylist:
        print(num)

* 7. for... in... The Nature of Cycle

The essence of the iterator loop for item in Iterable is to obtain the iterator of Iterable by iter() function, and then call next() method to get the next value and assign it to item. When the exception of StopIteration is encountered, the loop ends.

8. Application scenarios of iterators

We find that the core function of the iterator is to return the next data value by calling the next() function. If the data value returned each time is not read in an existing data set, but generated by the program according to certain rules, then it means that we can no longer rely on an existing data set, that is to say, we do not need to cache all the data to be iterated at one time for subsequent sequencing. Read, which can save a lot of storage (memory) space.

For example, in mathematics, there is a famous Fibonacci sequence, in which the first number is 0 and the second number is 1. Each subsequent number can be added up by the first two numbers:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

Now we want to pass for... In... The first n numbers in the iterated Fibonacci sequence are traversed by a loop. So this Fibonacci sequence can be implemented by an iterator. Each iteration generates the next number by mathematical calculation.

class FibIterator(object):
    """Fibonacci sequence iterator"""
    def __init__(self, n):
        """
        :param n: int, Specifies the front of the generated sequence n Number
        """
        self.n = n
        # Currt is used to save the number of current ly generated numbers in a sequence
        self.current = 0
        # num1 is used to save the previous number, and the initial value is the first number 0 in the sequence.
        self.num1 = 0
        # num2 is used to save the previous number, with the initial value being the second number 1 in the sequence.
        self.num2 = 1

    def __next__(self):
        """cover next()Function calls to get the next number"""
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """Iterator__iter__Just go back to yourself."""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print(num, end=" ")

9. It's not just for loops that can receive iterative objects

In addition to for loops, list s, tuple s, and so on can receive iterative objects.

li = list(FibIterator(15))
print(li)
tp = tuple(FibIterator(6))
print(tp)

 

Posted by ajenkins198621 on Sun, 04 Aug 2019 23:01:37 -0700