Catalog
Concept of generator
Create one of the generators
Create generator two
Create generator three
The execution process of the generator
Generated by list , We can create a list directly . however , Limited by memory , List capacity must be limited .
and , Create a containing 100 List of ten thousand elements , It takes up a lot of storage space , If we just need to access the first few elements , Most of the space occupied by the elements behind that is wasted .
therefore , If list elements can be calculated by some algorithm , Then can we constantly calculate the following elements in the process of circulation ? So you don't have to create a complete list, To save a lot of space .
stay Python in , This kind of mechanism of calculating while cycling , It's called a generator :generator. The generator object is an iterator : But it has a few more methods than iterator objects , They include send Method ,throw Methods and close Method . These methods , It is mainly used for external interaction with generator objects .
To create a generator, There are many ways . The first method is simple , Just put a list into a generative [] Change to (), You create a generator:
L = [x * x for x in range(10)] # List generator
The result is :[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10)) # generator
<generator object <genexpr> at 0x1022ef630>
establish L and g The difference is only in the outermost [] and (),L It's a list, and g It's a generator.: Can pass next() Function to obtain generator Next return value of , The instruction throws an exception :“StopIteration”
next(g)
The result is :0
next(g) ,# And so on
Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration
We talked about ,generator The saved algorithm , Every time you call next(g), Just figure it out g The value of the next element of , Until the last element , Without more elements , Throw out StopIteration Error of .
Can pass for Loop creation generator , because generator It's also an iterative object :
g = (x * x for x in range(10))
for n in g:
print(n)
therefore , Created a generator after , Basically through for Loop to iterate over it , And don't care StopIteration Error of .
generator Very powerful . If the algorithm is complex , Using something like list generation for When the loop doesn't work , You can also use functions to implement . such as , The famous fiboracci series (Fibonacci), Except for the first and second numbers , Any number can be obtained by adding the first two numbers :1, 1, 2, 3, 5, 8, 13, 21, 34, ..., Fiboracci series can't be written in tabular form , however , It's easy to print it out with a function :
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
Be careful , Assignment statement :
a, b = b, a + b
amount to :
t = (b, a + b) # t It's a tuple
a = t[0]
b = t[1]
Artifact : You can assign values without explicitly writing out temporary variables .
The function above can output the first part of Fibonacci sequence N Number :
fib(6)
Observe carefully , It can be seen that ,fib Function actually defines the calculation rules of fiboracci sequence , You can start with the first element , Extrapolate any subsequent elements , This logic is very similar generator, But it's not generator.
hold fib Functions into generator, Only need to print(b) Change it to yield b That's all right. :
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
That's the definition generator Another way . If a function definition contains yield keyword , So this function is no longer a normal function , It is a generator:
f = fib(6)
<generator object fib at 0x104feaaa0>
The hardest thing to understand is generator It's not the same as the execution flow of a function . Functions are executed sequentially , encounter return Statement or the last line of function statement returns . And become generator Function of , On each call next() When it comes to execution , encounter yield Statement returns , From the last returned... When executing again yield Statement to continue execution .
A simple example , Define a generator, Return the numbers one by one 1,3,5:
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
Call the generator when , The first thing to do is to generate a generator object , And then use next() The function continues to get the next return value :
o = odd()
next(o)
#step 1
#1
next(o)
#step 2
#3
next(o)
#step 3
#5
next(o)
#Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration
You can see ,odd It's not a normal function , It is generator, In the process of execution , encounter yield Just interrupt , Next time, we will continue to implement . perform 3 Time yield after , No more yield It can be carried out , therefore , The first 4 Secondary call next(o) Just report a mistake . Change the function to generator after , Basically never use next() To get the next return value , But directly for Loop to iterate :
for n in fib(6):
print(n)