Reference link: Generator in Python
The concept of iteration
The result of the previous output is the initial value of the next input. The repeated process is called iteration. Each repetition is one iteration, and the result of each iteration is the initial value of the next iteration.
What is iteration
A way to access collection elements. Objects that can be traversed through a for loop are called iterable objects. Numerical types are not iterable.
Determine whether the object is iterable: isinstance() Determine whether it is Iterable (iterable object)
from collections.abc import Iterable
print(isinstance([1,2,3,4],Iterable))
Is an iterable object returns True
Is not an iterable object returns False
Iterable object
The built-in iter method is an iterable object. List is an iterable object, dict is an iterable object, and set is also an iterable object.
Iterator
Why is there an iterator? For data types without indexes, an iterative method that does not rely on indexes must be provided.
Iterator definition: Iterator: the iterable object executes the iter method, and the result obtained is the iterator. The iterator object has the next method
It is a stateful object. It can return the next value in the container when you call the next() method. Any object that implements the iter and next() methods is an iterator. Iter returns the iterator itself, next Return the next value in the container, if there are no more elements in the container, throw StopIteration exception
The iterator's traversal loop:
class MyIterator(object):
def init(self,list):
self.list=list
self.xiabiao=0
def iter(self): #Get iterator, itself is an iterator, so return itself
return self
def next(self): #Get the next data in the iterator
if self.xiabiao < len(slef.list):
item=self.list[self.xiabiao]
self.xiabiao += 1
return item
else:
raise StopIteration #throwing stop iteration exception
a=[11,22,33,44,55]
my=MyIterator(a)
for i in my:
print(i)
The essence of the for...in... loop: First obtain the iterator of the iterable object through iter( ), and then continuously use the next() method on the obtained iterator to get the next value, and assign it to a variable, when it encounters StopIteration End of loop
while True:
try:
print(next( ))
except StopIteration:
break
Application scenarios of iterators: Fibonacci sequence
class Fei(object):
def init(self,n):
self.n=n
self.weizhi=0 record location
self.num1=0 defines the initial variable
self.num2=1
def iter(self): Get iterator, this class itself is iterator, return itself
return self
def next(self): Get the next data in the iterator
if self.weizhi < self.n:
num=self.num1
self.num1,self.num2=self.num2,self.num1+self.num2
self.weizhi += 1
return num
else:
raise StopIteration
fei=Fei(10)
for i in fei:
print(i)
Three ways to view iterator data: for, list, tuple
for i in fei:
print(fei)
print(list(fei))
print(tuple(fei))
Generator
The generator is a special iterator, its implementation is simpler and more elegant, and yield is the key to the next() method of the generator. It serves as the pause and resume point of the generator execution. It can assign a value to the yield expression, and it can also return the value of the yield expression. In other words, yield is a syntactic sugar, the internal implementation supports the iterator protocol, and the internal yield is a state machine that maintains the suspended and continued state. A generator can be understood as a data type. This data type automatically implements the iterator protocol (other data types need to call its own built-in iter method). In Python, the mechanism of looping while calculating is called a generator.
The function of yield:
It is equivalent to encapsulating a function that iter and nextreturn can only return the value once, the function is terminated, and yield can return multiple values, each return will pause the function, and the next next will continue to execute from the last paused position to save the current Running state, pause execution, return the value of the expression after the yield keyword as the return value, which can be understood as playing the role of return
The role of the generator
Through list generation, we can directly create a list, but due to memory limitations, the list capacity is definitely limited. Moreover, creating a list of 1 million elements not only takes up a lot of storage space, but if we only need to access the first few elements, the space occupied by most of the latter elements is wasted. Therefore, if the list elements can be calculated according to a certain algorithm, can we continue to calculate the subsequent elements in the loop? This eliminates the need to create a complete list, which saves a lot of space. In Python, this mechanism of calculating while looping is called generator: generator.
How the generator works
A generator is a function that remembers its position in the body of the function the last time it returned. The second (or nth) call to the generator function jumps to the middle of the function, and all local variables of the last call remain unchanged. The generator not only "remembers" its data state; the generator also "remembers" its position in the flow control structure. The generator is a function, and the parameters of the function are retained. When iterating to the next call, the parameters used are all reserved for the first time, that is to say, the parameters of all function calls are reserved for the first call instead of newly created
The operating mechanism of the yield generator is in Python, and yield is such a generator.
When you ask the generator for a number, the generator will execute until a yield statement appears, and the generator will give you the yield parameter, and then the generator will not continue to run. When you ask him for the next count, he will run from the previous state until the yield statement appears, give you the parameters, and then stop. So repeatedly in python, when you define a function and use the yield keyword, this function is a generator. Its execution will be different from other ordinary functions. The function returns an object, not what you usually use. Like the return statement, the result value can be obtained. If you want to get the value, you have to call the next() function. Whenever you call the next function of the iterator, the generator function runs to the yield point, returns the value after the yield and pauses at this point, all the state will be maintained. Until the next function is called next time, or encounter an abnormal loop exit.
Why is a generator an iterator? Python's standard for judging whether an object is an iterator is to see whether the object complies with the iterator protocol, and judging whether an object complies with the iterator protocol mainly depends on two aspects:
The object must first implement the iter and next methods, and then the iter method must return itself
The generator just meets these two conditions (you can write a generator yourself, and then call these two methods of the generator to try). We often encounter another concept: iterable objects. An iterable object is an iterable object, and an iterable object means that we can get an iterator from this object. In Python, the iter method can help us accomplish this, that is, iterable objects and iterators satisfy such a relationship: iter(iterable) -> iterator.
In Python, list is an iterable object, so we often write code like this:
l = [1, 2, 3]
for element in l:
print(element)
But have you ever wondered why we can write like this? Why in C language, when we access array elements, we must pass index?
Because: list is an iterable object, when we use for… in in Python, Python will generate an iterator object for us, and as mentioned above: an iterator is a data stream, it can generate data, we always get data from it That's fine, we don't need to maintain the index in the code, Python has done this for us through iterators.
Build the generator: Change the square brackets of the list comprehension to parentheses
g=(i for i in range(1,11))
print(g)
Use yield to construct Fibonacci sequence
def fei(n):
num1,num2=0,1
weizhi=0
while weizhi < n :
num=num1
num1,num2=num2,num1+num2
weizhi += 1
yield num
print(list(fei(10)))
Wake-up generator: send( ), next( ), next()
send( )
ret=fei(10)
a=ret.send(None)
print(a)
next( )
ret=fei(10)
while True:
try:
print(next(ret))
except StopIteration:
break
The difference between generators and iterators
When using a generator, we create a function; when using an iterator, we use the built-in functions iter() and next(). In the generator, we use the keyword'yield' to generate/return an object at a time. You can customize how many'yield' statements there are in the generator. Every time'yield' pauses the loop, the generator saves the state of the local variables. The iterator does not use local variables, it only needs an iterable object for iteration. Use classes to implement your own iterators, but not generators. The generator runs fast, the syntax is concise and simpler. Iterators can save more memory.
Recommended Posts