Builder
Through list comprehension, I can directly create a list, but due to memory constraints, the capacity of the list is definitely limited, and creating a list containing 1 million elements not only takes up a lot of storage space, if we only need to access the front A few elements, then the space occupied by most of the elements behind is wasted.
So, if the elements of the list can be calculated according to a certain algorithm, can we continue to calculate the subsequent elements in the process of looping? This saves a lot of space by not having to create a complete list. In Python, this mechanism of computing while looping is called a generator: generator.
To create a generator, there are many ways. The first method is very simple, as long as a list comprehension is []
changed ()
to create a generator:
L = [X * X for x in range(10)]
print(l)
[
0
,
1
,
4
,
9
,
16
,
25
,
36
,
49
,
64
,
81
]
The generator is created.
g = (x * x for x in range(10))
print(g)
<generator
object
<genexpr> at
0x1022ef630
>
The difference between creating a L
sum g
is that the outermost []
sum is a list ()
, butL
a generator.g
We can print out each element of the list directly, but how do we print out each element of the generator?
If you want to print them out one by one, you can next()
get the next return value of the generator through the function:
next(g)
0
next(g)
1
next(g)
4
next(g)
8
next(g)
9
next(g)
10
>>>
next
(g)
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
StopIteration
next(g)
, it calculates the value of
g
the next element until the last element is calculated, and when there are no more elements,
StopIteration
an error is thrown.
next(g)
above is too perverted. The correct way is to use a
for
loop, because the generator is also an iterable object:
So, after we create a generator, it is basically never called next()
, but for
iterates through a loop and doesn't need to care about StopIteration
errors.
generators are very powerful. If the calculation algorithm is complex and for
cannot be implemented by a loop similar to the list generation type, it can also be implemented by a function.
For example, in the famous Fibonacci sequence, any number except the first and second numbers can be obtained by adding the first two numbers:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
The Fibonacci sequence cannot be written with list comprehension, but it is easy to print it with a function:
def fib(mix):
n,x,y, = 0,0,1
while n < mix:
print(b)
a,b = b, a+b
n = n+1
return 'ss'
Note that the assignment statement
a,b = b, a+b
is equivalent to:
t = (b,a+b) t is a tuple
a = t[0]
b = t[1]
But you can assign a value without explicitly writing out the temporary variable t.
fib
The function actually defines the calculation rules of the Fibonacci sequence. It can start from the first element and calculate any subsequent elements. This logic is actually very similar to the generator.
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 return 'done'
yield
keyword , then the function is no longer a normal function, but a generator:
return
statement or the last line of the function statement is encountered. The function that becomes the generator is executed every time it is called
next()
, and it
yield
returns when it encounters a statement. When it is executed again, it continues to execute from the last returned
yield
statement .
在上面fib
example, we keep calling during the loop yield
, it will keep breaking. Of course, a condition must be set for the loop to exit the loop, otherwise an infinite number list will be generated.
Similarly, after changing the function to a generator, we basically never use it next()
to get the next return value, but directly use the for
loop to iterate:
But for
when the generator is called with a loop, it is found that the return value of the generator's return
statement cannot be obtained. If you want to get the return value, you must catch the StopIteration
error, and the return value is contained StopIteration
in value
:
g
=
fib(
6
)
while
True
:
try
:
x
=
next
(g)
print
(
'g:'
, x)
except
StopIteration as e:
print
(
'Generator return value:'
, e.value)
break
import time def consumer(name): print("%s is ready to eat buns!" %name) while True: baozi = yield print("Baozi [%s] came and was eaten by [%s]!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("I'm ready to make buns!") for i in range(10): time.sleep(1) print("Make 2 buns!") c.send(i) c2.send(i) producer("alex")