生成器

生成器概念:在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用最简便的语法,即生成器。生成器是一类特殊的迭代器。

创建生成器的方法:

  1.使用元组推导式

1 import random
2 
3 numbertuple = (random.randint(10, 100) for i in range(10))
4 print(numbertuple)    # 生成的numbertuple是一个生成器对象
5 
6 # 可以使用for循环提取生成器对象中的元素的值
7 for num in numbertuple:
8     print(num)

  运行结果:

<generator object <genexpr> at 0x00000000025FE740>
21
57
31
31
97
58
52
93
73
11

  2.自己定义生成器(函数)——函数中含有yield,创建出的变量即是生成器

 1 def create_num(all_num):
 2     a, b = 0, 1
 3     current_num = 0
 4     while current_num < all_num:
 5         yield a   # 如果一个函数中有yield语句,那个这个就不再是函数,而是生成器的模板
 6         a, b = b, a+b
 7         current_num += 1
 8     return "OK"
 9 
10 
11 # 如果在调用creat_num函数的时候,发现这个函数中有yield
12 # 那么此时,不是调用函数,而是创建一个生成器对象,此时的fibo就是一个生成器对象
13 fibo = create_num(10)

  可以使用for循环提取生成器中的元素的值:

 1 for num in fibo:
 2     print(num)
 3 
 4 
 5 # 运行结果:
 6 0
 7 1
 8 1
 9 2
10 3
11 5
12 8
13 13
14 21
15 34

  利用next函数提取生成器中元素的值:

 1 # next函数执行步骤:第一次执行会从含yield的函数的开头执行,当执行到yield时函数执行暂停
 2 # 将yield后面的值返回,返回到调用next函数代码位置
 3 obj = next(fibo)
 4 print(obj)
 5 
 6 # 第二次执行会从函数yield暂停位置继续向下执行,当再次执行到yield时函数再次暂停
 7 # 将yield后面的值返回,返回到调用next函数代码位置
 8 obj = next(fibo)
 9 print(obj)
10 
11 # 运行结果:
12 0
13 1

  利用next函数循环提取生成器中元素的值,提取完退出程序:

 1 while True:
 2     try:
 3         ret = next(fibo)
 4         print(ret)
 5     except StopIteration as ret:
 6         break
 7 
 8 # 运行结果:
 9 
10 0
11 1
12 1
13 2
14 3
15 5
16 8
17 13
18 21
19 34
20 OK

  如果生成器的模板(函数)中含有return的返回值,可以在异常中通过异常.value获取这个返回值:

 1 def create_num(all_num):
 2     a, b = 0, 1
 3     current_num = 0
 4     while current_num < all_num:
 5         yield a   
 6         a, b = b, a+b
 7         current_num += 1
 8     return "OK"
 9 
10 fibo = create_num(10)
11 
12 while True:
13     try:
14         ret = next(fibo)
15         # print(ret)
16     except StopIteration as ret:
17         # test = ret.value
18         # print(test)
19         print(ret.value)
20         break
21 
22 # 运行结果:
23 OK

  除了通过next函数提取生成器中的元素的值外,还可以通过send函数提取,send函数可以传一个参数到生成器的模板(函数)内:

 1 def create_num(all_num):
 2     a, b = 0, 1
 3     current_num = 0
 4     while current_num < all_num:
 5         yield a  
 6         a, b = b, a+b
 7         current_num += 1
 8 
 9 fibo = create_num(10)
10 
11 obj = next(fibo)
12 print(obj)
13 
14 ret = fibo.send("hello python")
15 print(ret)
16 
17 # 运行结果:
18 0
19 hello python
20 1

  send函数使用场景:当取生成器元素的值到一定程度时,不想取下一个值而想从某次往后重新取值,可以使用send函数传一个值到生成器内部,yield在前面用一个变量=yield来接收,传入的值传给这个变量。例如:

 1 def create_num(all_num):
 2     current_num = 1
 3     while current_num < all_num:
 4         a = 2**current_num
 5         ret = yield a
 6         if ret != None:
 7             current_num = ret-1
 8         current_num += 1
 9 
10 
11 obj = create_num(10)
12 
13 ret = next(obj)
14 print(ret)
15 
16 ret = next(obj)
17 print(ret)
18 
19 ret = next(obj)
20 print(ret)
21 
22 ret = next(obj)
23 print(ret)
24 
25 ret = next(obj)
26 print(ret)
27 
28 ret = next(obj)
29 print(ret)
30 
31 ret = obj.send(3)   # 从第3次往后重新取值
32 print(ret)
33 
34 ret = next(obj)
35 print(ret)

  运行结果:

2
4
8
16
32
8
16

 

posted @ 2020-04-10 22:57  组装梦想  阅读(129)  评论(0编辑  收藏  举报