3, Generator / iterator


1, Iterator / iteratable object

 1. Iteratable object (memory cost)

The old version of python: range consumes more memory (all the data needed are stored in the list, which is very memory consuming when the amount of data is large)

range implementation process:

from typing import Iterable

def range_test(stop):
    start = 0
    result = []
    while start < stop:
        start += 1
    return result

if __name__ == '__main__':
    print(isinstance(range_test(10),Iterable))  # Judge whether the returned result is iterative, True
    print(range_test(10))                     # output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 2. Iteratable object (memory saving)


from typing import Iterable

# Next contain__next__()Method, each variable+1,Only one number of memory is used at a time
class Next(object):
    """Next class"""

    def __init__(self, stop, start=-1):
        self.start = start
        self.stop = stop

    def __next__(self):
        if self.start >= self.stop - 1:
            raise StopIteration
        self.start += 1
        return self.start


# contain__iter__()method, return call Next
class MyRange:

    def __init__(self, stop):
        self.stop = stop

    def __iter__(self):
        return Next(self.stop)

Using the mode mode and single step execution, you can see that the program executes Next, and each execution generates a data. No memory consumption

for is an iteration (automatically executing _ ITER _, _ next), while is a loop (specify the function manually)

if __name__ == '__main__':
    print(Next(10).__next__())  # 0
    for item in MyRange(10):  # for Loop automatic execution__iter__,__next__method
    # while loop
    num = MyRange(10).__iter__()
    i = 0
    while i < 10:
        print(num.__next__())  # 0,1,2,3,4,5,6,7,8,9
        i += 1

3. Iterative object definition

Objects that can be iterated by for are iteratable objects

Object has__ iter__ Methods are all iteratable objects (if there is no _iter _method, it cannot be iterated by for)__ iter__ It is required that the return value must be an iterator (strictly speaking, the return value must have a _next _method)

Common iteratable objects; list,tuple,string,dict

Determine whether each object is an iteratable object:

  1. You can use dir() to check whether there is any in all attributes__ iter__ method

  2. You can also use hasattr (list, '_iter_') to check whether the list has__ iter__ method. If True is returned, the method is available

Judge whether MyRange(10) is an iterative object:

If print (isinstance (MyRange(10), iteratable) returns True, then MyRange(10) is an iteratable object because there are__ iter__ method

Judge whether Next(10) is an iterative object:

If print (isinstance (Next(10), iteratable) returns False, then Next(10) is not an iteratable object because there is no__ iter__ method

4. Iterator definition

Iterators must have__ iter__    __ next__ Attributes

Core: Pass__ next__ Method to remember the location of the iteration and whether the iteration has been completed

Iterators are special iteratable objects,

It can be iterated by for. When the iterator is iterated by for, it will be executed automatically__ next__ method

Iterators save more memory and give only one number at a time.

Without an iterator, you can't use for, you can only use while

Determine whether Next(10) is an iterator

print(isinstance(Next(10),Iterator) # fast__ next__ Method, but missing__ iter__ method

Note:__ iter__ An iterator must be returned (strictly speaking, the return value must have a _next _method)

2, Generator

Because it is troublesome to implement iterators manually

So python provides a generator object, and the purpose of the generator object is to obtain the iterator object (very efficient)

def fun():
    print("stay yield1 front")
    yield 1
    print("stay yield1 Back, yield2 front")
    yield 2

if __name__ == '__main__':
    # Verify whether it is a generator
    print(fun())   # <generator object fun at 0x104d00150> The result is a generator object, but no function is running
    print(hasattr(fun(),"__iter__"))  # True
    print(hasattr(fun(),"__next__"))  # True

    # To run the generator, you must call__next__
    print(fun().__next__())  # 1 / stay yield1 front
    # Run all results,for Automatic call__next__
    for i in fun():

be careful:

  • When the python interpreter sees that there is a yield in the function, it will not call the function immediately, but create a generator object first. The generator object remembers the state of the function

  • In the for loop, when it runs to the first yield, it exits temporarily (similar to return, but the difference is that return jumps out permanently and won't go back). When you run again (_next_ remember the location), you will start running after yield 1

  • When next is executed, the yield of the generator object is executed

Generators are special iterators, which are special iteratable objects

Generators are iteratable objects

If you create a generator object (via yield)

yield: Keyword

Remember the state of function execution

When next(g) is executed, yield in G is executed

The difference between yield and return:

return: jump out of the function and don't come back

yield: jump out temporarily and come back

Usage scenario of generator:


Why does the generator save memory: because there are__ next__

The generator is designed to quickly obtain__ iter__   __ next__ Method of

Scenario 1: I need 99999999999999 numbers, and put 1-99999999999999 numbers in the list at once

Scenario 2: I need 999999999999 numbers. I need 1 to generate 1, I need 2 to generate 2 ~ ~ ~ ~ ~ I need 9999999999999 to generate 99999999999

Scenario 2 is the idea of next (generator and iterator)


Reproduced for reference only: http://testingpai.com/article/1605148018144  

Posted by chico1st on Fri, 06 May 2022 00:50:58 +0300