Python生成器入门指南

Python中有一个神奇的东西叫做生成器。
什么是生成器?
——形式地看,python语言中一旦关键字 yield出现,就表示一个生成器诞生了。

为了减少我们对生成器的恐惧和陌生感,让我们看一个简单的例子:

def fib():
    a, b = 0, 1
    while 1:
       yield b
       a, b = b, a+b

这段代码在做什么?作为一个对python有一定了解的同学,他几乎一眼就能看出来,这可能是一个生成斐波那契数序列的代码(yield的出现,可能会带来一点困惑)
这段代码中,fib在python解释器的存在形式是 generator 生成器。
且看

>> dir(fib())
>> print (type(fib()))

分别输出:

['class', 'delattr', 'doc', 'format', 'getattribute', 'hash', 'init', 'iter', 'name', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

以及

<type 'generator'>

在dir(fib())中 我们可以看到fib实现了iter协议,说明它是一个可迭代的对象。可以像放到这样的句法当中:

for item in fib():
      pass

生成器是重载了iter方法的可迭代对象

任何函数带 yield都会自动转换成生成器

例子:

def foo_func():
    print "> May not be printed this line"  (1)
    exit()
    yield "> This is generator"
    
foo_func()

调用 foo_func() 会发现 第(1)行不会打印

这是因为

关键字 yield 一旦出现在函数内部 函数就会自动转为一个生成器,生成器只有使用next方法才会被调用

如上

x = foo_func()
print(next(x))

生成器内置迭代器,请看:

dir(x) #x是一个生成器

[
'__class__', '__del__', '__delattr__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__',
'__le__', '__lt__', '__name__', '__ne__', '__new__',
'__next__', '__qualname__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__',
'close', 'gi_code', 'gi_frame', 'gi_running',
'gi_yieldfrom', 'send', 'throw'
]

生成器对象实现了 iter 协议,因此它是可迭代对象,可以使用for Loop迭代

例子:

def one_to_ten():
    val = 1
    while val <= 10:
        #print val
        yield val
        val += 1

for ele in one_to_ten():
    print ele
  • 生成器 是一种特殊的迭代器

  • 一旦一个函数中包含了关键字 yield 那么它就会自动转化为一个生成器

  • 生成器有异于一般函数的使用方式

神奇的yield

当一个生成器函数的 yield 被调用的时候,函数的内部状态就被“冻结”起来,函数内部的变量和值被保存起来。
下一行的代码直到next()方法调用才会再次被执行

next执行的时候,生成器在它上次被中断的地方恢复所有状态,并继续执行,直到下一个yield出现


def is_prime(number):
    if number == 2:
        return True

    i = 2
    while i * i <= number:
        if number % i == 0:
            return False
        i += 1
    else:
        return True


def get_prime(number):
    while True:
        if is_prime(number):
            yield number
        number += 1

for element in get_prime(2):
    print(element)

记住这些:

  • generators 用来生成一系列的值
  • yield 在生成器中的作用类似于 return;区别在于,yield保存了函数的局部状态,但return在函数中,会转移控制权,导致整个函数内部丢失所有状态
  • 生成器是一种特殊的迭代器(即它实现了内部协议 iter)因此像迭代器一样,生成器可以用next()得到下一个值

PEP 255 - 简单生成器

在 Python 中加入生成器和 yield 语句的提议。

PEP 342 - 通过增强型生成器实现协程</dt>

增强生成器 API 和语法的提议,使其可以被用作简单的协程。

PEP 380 - 委托给子生成器的语法

引入 yield_from 语法以方便地委托给子生成器的提议。

PEP 525 - 异步生成器</dt>

通过给协程函数加入生成器功能对 PEP 492 进行扩展的提议。

</dd>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容