Python之生成器

生成器是一种特殊的迭代器

1. 如何构造一个生成器

In [6]: li = [item for item in range(10)] 
   ...: print(li) 
   ...: ge = (item for item in range(10)) 
   ...: print(ge)                                                                             
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 at 0x7fee50aaf048>

可以看到上面的创建方式的不同来自于[ ] ( ),但创建出来的一个是列表,一个是生成器,我们可以使用next()方法和for循环来调用生成器

In [7]: ge = (item for item in range(4)) 
   ...: print(next(ge)) 
   ...: print(next(ge)) 
   ...: print(next(ge)) 
   ...: print(next(ge)) 
   ...: print(next(ge))                                                                       
0
1
2
3
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
 in 
      4 print(next(ge))
      5 print(next(ge))
----> 6 print(next(ge))

StopIteration: 
In [8]: ge = (item for item in range(4)) 
   ...: for i in ge: 
   ...:     print(i) 
   ...:                                                                                       
0
1
2
3

2. 构造生成器的另一种方式

首先我们回顾下迭代器,前面说过生成器是一种特殊的迭代器
首先我们先使用迭代器实现斐波那契数列,然后在使用生成器来实现,来比较两者的不同
使用迭代器来实现

In [9]: class Fibo(object): 
   ...:     def __init__(self, count): 
   ...:         self.start = 0 
   ...:         self.end = 1 
   ...:         self.current = 0 
   ...:         self.count = count 
   ...:          
   ...:     def __next__(self): 
   ...:         if self.current <= self.count: 
   ...:             fibo = self.start 
   ...:             self.start, self.end = self.end, self.end+self.start 
   ...:             self.current += 1 
   ...:             return fibo 
   ...:         else: 
   ...:             raise StopIteration 
   ...:      
   ...:     def __iter__(self): 
   ...:         return self 
   ...:      
   ...: fibo = Fibo(10) 
   ...: for i in fibo: 
   ...:     print(i) 
   ...:                                                                                       
0
1
1
2
3
5
8
13
21
34
55

使用生成器来实现

In [10]: def Fibo(n): 
    ...:     count = 0 
    ...:     start, end = 0, 1 
    ...:     while count <= n: 
    ...:         fibo = start 
    ...:         start, end = end, start+end 
    ...:         count += 1 
    ...:         yield fibo 
    ...:     return 'None' 
    ...:  
    ...: fibo = Fibo(10) 
    ...: for i in fibo: 
    ...:     print(i) 
    ...:                                                                                      
0
1
1
2
3
5
8
13
21
34
55

3. 小结

  • 函数中使用了yield关键字的都是生成器
  • yield关键字的作用
    • yield起到了return的作用,返回它后面的值
    • yield保存了当前运行状态,暂停执行,也就是将函数挂起
  • 使用next()将函数唤醒,继续执行
  • python3中使用yield最终可以使用return来返回一个值,这个值需要捕获StopIteration,python2中不允许使用return返回一个返回值

4. 使用send()来唤醒

除了使用next()函数来唤醒生成器之外,send()函数也可以唤醒。使用send()函数的一个好处是可以向断点传入数据。

In [11]: def gene(): 
    ...:     count = 0 
    ...:     while count < 5: 
    ...:         yield count 
    ...:         count += 1 
    ...: g = gene() 
    ...: print(next(g)) 
    ...: print(next(g)) 
    ...: print(next(g)) 
    ...: print(next(g)) 
    ...: print(next(g)) 
    ...: print(next(g))                                                                       
0
1
2
3
4
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
 in 
     10 print(next(g))
     11 print(next(g))
---> 12 print(next(g))

StopIteration: 
In [12]: def gene(): 
    ...:     count = 0 
    ...:     while count < 5: 
    ...:         temp = yield count 
    ...:         print(temp) 
    ...:         count += 1 
    ...:          
    ...: g = gene() 
    ...: print(next(g)) 
    ...: print(g.send("a")) 
    ...: print(g.send("b")) 
    ...: print(g.send("c")) 
    ...: print(g.send("d")) 
    ...: print(g.send("e")) 
    ...: print(g.send("f"))                                                                   
0
a
1
b
2
c
3
d
4
e
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
 in 
     12 print(g.send("c"))
     13 print(g.send("d"))
---> 14 print(g.send("e"))
     15 print(g.send("f"))

StopIteration: 

使用send()函数来向temp变量来传递一个值,生成器在第一次执行时,碰到yield会挂起,而这时send()函数传递的值没有变量去接收,这就会报错,所以第一次的执行应该是next()函数,如果send()函数为第一次执行,那么,send()传递的变量应该为None。

In [13]: def gene(): 
    ...:     count = 0 
    ...:     while count < 3: 
    ...:         temp = yield count 
    ...:         print(temp) 
    ...:         count += 1 
    ...:          
    ...: g = gene() 
    ...: print(g.send("a")) # 第一次使用send()来执行 
    ...: print(g.send("b")) 
    ...: print(g.send("c"))                                                                   
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in 
      7 
      8 g = gene()
----> 9 print(g.send("a")) # 第一次使用send()来执行
     10 print(g.send("b"))
     11 print(g.send("c"))

TypeError: can't send non-None value to a just-started generator
In [14]: def gene(): 
    ...:     count = 0 
    ...:     while count < 3: 
    ...:         temp = yield count 
    ...:         print(temp) 
    ...:         count += 1 
    ...:          
    ...: g = gene() 
    ...: print(g.send(None)) # 第一次使用send()来执行,但是传递的参数是None 
    ...: print(g.send("b")) 
    ...: print(g.send("c"))                                                                   
0
b
1
c
2

你可能感兴趣的:(Python之生成器)