Python3的生成器generator(1)

虽然生成器可以让你编写出优雅的代码,但它并不是不可或缺的。

生成器是一种使用普通函数语法定义的迭代器。

例1:创建一个将嵌套列表展开的函数

 1 # 创建一个将嵌套列表展开的函数
 2 # 给出的嵌套列表 nested:嵌套
 3 nested = [[1,2],[3,4]]
 4 
 5 def flatten(nested):
 6     for sublist in nested:
 7         for element in sublist:
 8             yield element  # yield每生成一个值后,函数都将冻结,被重新唤醒后,函数将从停止的地方开始继续执行
 9 
10 for n in flatten(nested):
11     print(n)

输出:

1

2

3

4

当然我们可以将for循环换成:

print(list(flatten(nested)))

输出:[1, 2, 3, 4]

例2:递归生成器

1 # 创建一个能够处理任意层嵌套的列表
2 def flatten(nested):
3     try:
4         for sublist in nested:
5             for element in flatten(nested):
6                 yield element
7     except TypeError:
8         yield nested

处理递归时,有两种可能:基线条件和递归条件

基线条件下,要求这个函数展开单个元素(如一个数)。这种情况下,for循环将引发TypeError异常(因为你试图迭代一个数),而这个生成器只生成一个元素。

 如果要展开的是一个列表(或其他任何可迭代的对象),则需要:遍历所有的子列表(有些可能不是列表)并对它们调用flatten,然后使用另一个for循环展开后的子列表中的所有元素。

注意:

如果nested是字符串或类似字符串的对象,它就属于序列,因此不会引发TypeError异常,可你并不想对其进行迭代。

因为:

① 你想将类似于字符串的对象视为原子值,而不是应该展开的序列;

② 对这样的对象迭代会导致无穷递归。因为字符串的第一个元素是一个长度为1的字符串,而长度为1的字符串的第一个元素是字符串本身。

要处理这种问题,必须在生成器开头进行检查。

例3:添加检查对象是否类似于字符串

 

 1 def flatten(nested):
 2     try:
 3         # 不迭代类似字符串的对象
 4         try: nested + ''
 5         except TypeError: pass
 6         else: raise TypeError
 7         for sublist in nested:
 8             for element in flatten(nested):
 9                 yield element
10      except TypeError:
11         yield nested

如果表达式nested + ''引发了TypeError异常(说明nested不是类字符串对象),就忽略这种异常;

如果没有引发(说明nested是类字符串对象),则通过else引发。这样将在外部的except子句中原封不动地生成类似于字符串的对象(因为加的''对原字符串没有任何影响)。

当然,我们也可通过isinstance检查

例4:通用生成器

生成器是包含yield关键字的函数,但被调用时不会执行函数体内的代码,而是返回一个迭代器。

每次请求值时,都将执行生成器的代码,直到遇见yield或者return。

yield意味着应生成一个值;

return意味着生成器应停止执行(即不在生成值;当且仅当在生成器调用return时,才能不提供任何参数)

 

posted @ 2018-06-07 00:10  无证骑士  阅读(178)  评论(0编辑  收藏  举报