Python yield

在 Python 中,使用了 yield 的函数被称为生成器 (generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单的理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值,并在下一次执行 next() 方法时从当前位置继续运行

调用一个生成器函数,返回的是一个迭代器对象。



实例:斐波那契数列

斐波那契数列是一个简单的递归,除第一个和第二个数外,任意一个数可由前两个数相加得到。


方法1:简单输出斐波那契数列的前 N 个数

def fab(max):
    n, a, b = 0, 0, 1
    for n in range(max):
        print(b)
        a, b = b, a+b
        n = n+1
fab(5)

输出:

1
1
2
3
5

使用 print 打印导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法调用。


方法2:通过列表返回

def fab(max):
    n, a, b = 0, 0, 1
    L = []
    for n in range(max):
        L.append(b)
        a, b = b, a+b
        n = n+1
    return L

for i in fab(5):
    print(i)

输出:

1
1
2
3
5

返回 list 能满足复用性要求,但该函数在运行中占用的内存会随着参数 max 的增大而增大。

如果要控制内存,不要用 List 来保存中间结果,而是通过 iterable 来迭代


方法3:通过 iterable 对象来迭代

利用 iterable 把 fab 函数改写为一个 iterable 的 class。

class Fab(object):
    def __init__(self, max):
        self.max = max
        self.n, self.a, self.b = 0, 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.n < self.max:
            r = self.b
            self.a, self.b = self.b, self.a+self.b
            self.n = self.n + 1
            return r
        raise StopIteration()

for n in Fab(5):
    print(n)

输出:

1
1
2
3
5

Fab 类通过 __next()__ 不断返回数列的下一个数,内存占用始终为常数。

但是 class 改写的版本,代码比较繁琐。

既想保持代码的简洁,又想获得 iterable 的效果,使用 yield


方法4:yield

def fab(max):
    n, a, b = 0, 0, 1
    for n in range(max):
        yield b
        a, b = b, a+b
        n += 1

for n in fab(5):
    print(n)

输出:

1
1
2
3
5

仅把第一种方法的 print(b) 改为 yield b,即保持了代码的简洁性又获得了 iterable 的效果。

posted @ 2021-11-30 13:34  做梦当财神  阅读(163)  评论(0编辑  收藏  举报