4. Python3 中的生成器

我们在上一个博客Python3 迭代器中说明了如何通过类的方式产生可迭代数据(__next__和__init__)。而,能否利用普通函数的机制产生可迭代的数据呢(比列表更加高效)?答案是肯定的,这就是python的生成器:

生成器的基本目的

就是利用函数产生可迭代对象(数据),期望的使用方式是这样的

def func():
    lst = range(10)
    pass # 增加具体的某种操作
iterObj = func();
for i in iterObj:
    print(i); # 迭代操作

想想看哈,pass 位置如何处理才能返回一个可迭代对象?

  • 直接return lst 当然是ok的。这样子的问题在于迭代器相对于列表的优势就完全没有了,所以我们希望不凭借list的结构直接产生一个迭代器。次想法可否?

答案是完全可以:yield语句

注意, yield 是语句! 是一个关键字,和def、for、if 是一样的东东。更改之后的代码是这样的

>>> def func():
...     lst = range(10)
...     for i in lst:
...         yield(i) # 用不用括号都是一样的
... 
>>> IterObj  =  func(  )
>>> for it in IterObj :
...     print(it)
... 
0 1 2 3 4 5 6 7 8 9

任何包含yield语句的函数称为生成器(generator)。区别与普通函数有:

  1. 不像return 那样返回值,而是每次产生多个值。
  2. 每次产生一个值(使用yield语句),函数就会被冻结:即函数停在那点等待被重新唤醒。函数被重新唤醒后就从停止的那点继续执行。

高级用法

  • 可递归形成递归生成器
# 伪代码的形式
def flatten (somelist):
    if somelist has sublist:
        for sublist in somelist:
            flatten(sublist)
    else:
        yield somelist

这种伪代码很好理解,但是不是很好的python 语句。这种case可以利用异常来便捷的处理,好像大牛们都习惯这么用,开始还真有点不习惯

# try except 语句实现的迭代
>>> def flatten (somelist):
...     try:
...         for sublist in somelist: # if has sublist 
...             for  element in flatten(sublist):  # we need flatten it again
...                 yield element 
...     except TypeError: #   it is an element
...         yield somelist
... 
>>> lst = [[1,2,[3,4]],5,6,[7,8,[9,10,[11]]]]
>>> print(list(flatten(lst)))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  • 更多的语法检测功能(列表中string元素的检测)
# 伪代码的形式
def flatten (somelist):
    if somelist is not string:
        if somelist has sublist:
             for sublist in somelist:
                  flatten(sublist)
    else:
        yield somelist

具体的语句实现是这样的

# try except 语句实现
>>> def flatten (somelist):
...     try:
...         try:
...             somelist +''# only string can do this add(字符串拼接操作)
...         except TypeError: pass # not a string
...         else: raise TypeError     # is a string, end flatten operation
...         for sublist in somelist: # if has sublist 
...             for  element in flatten(sublist):  # we need flatten it again
...                 yield element 
...     except TypeError: #   it is an element
...         yield somelist
... 
>>> lst = [[1,2,[3,4]],5,6,[7,8,[9,10,[11]]],'abc',['d',['ef',['gh',['ijk']]]]]
>>> print(list(flatten(lst)))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 'abc', 'd', 'ef', 'gh', 'ijk']

好的,看到了这里,估计你也就会使用生成器了,采用生成器(yield函数)返回的迭代器(class),与自己用class生成的迭代器一样的使用,没有区别。

你可能感兴趣的:(4. Python3 中的生成器)