python生成器

2018-03-09  本文已影响0人  伟大的洪立

什么时生成器

通过列表生成式,我们可以直接创建一个列表。 但是, 受到内存的限制,列表的容量是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面的几个元素,那后面绝大多说元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法算出来,那么我们是否可以在循环的过程中不断推算出后续的元素呢? 这样就不必创建完整的list, 从而节省大量的空间。
在python中,这种一边循环一边计算的机制,称为生成器:generator

创建生成器的方法

1. 只要把一个列表生成式的[]改成()

生成器
可以通过 next() 函数获得生成器的下一个返回值
生成器
生成器保存的是算法, 每次调用next(G),就计算出G的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIeration异常。
当然这种不断调用next()方法太变态了, 所以,我们使用for循环,因为生成器也是可迭代对象。

yield

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。

def fib(times):
    n = 0
    a, b = 0, 1
    while n<times:
        print(b)
        a, b = b, a+b
        n += 1
    return 'done'

fib(5)

fib函数实际上是定义了斐波那契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素, 这种逻辑其实非常类似genertor。
只要把fib函数变成generator,只需要把print(b)改成yield b。

def fib(times):
    n = 0
    a, b = 0, 1
    while n<times:
        yield b
        a, b = b, a+b
        n += 1
    return 'done'

F = fib(5)
next(F)

在上面fib 的例子,在循环过程中不断调用 yield ,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fib(5) 不会执行 fib 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fib 函数内部的代码,执行到 yield b 时,fib 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

send

def gen():
    i = 0
    while i<5:
        temp = yield i
        print(temp)
        i += 1
f = gen()
next(f)

在代码中, 执行到yield时, gen函数作用暂时保存,返回i的值;temp接收下次.send('python'), send发送的过来的值,c.next()等价c.send(None)
send 主要是反向想函数中传递一个值
例如:

def demo():
  n = 10
  while n < 20:
    temp = yield n
    if temp == 1:
        print("查询了一条语句")
    elif temp == 2:
        print("更新了一条语句")
    elif temp == 3:
        print("删除了一条语句")
    n += 1
res = demo()
res.next()
res.send(1)
输出: 查询了一条语句
上一篇下一篇

猜你喜欢

热点阅读