浅谈Python yield使用

零零碎碎学着python已经好久了,但是总会发现有好些知识点都没学到,今天在牛客网看到了这样一道题:

# 下列代码的运行结果是什么?
def bar(n):
    m = n
    while True:
        m+=1
        yield m
b = bar(3)
print b.next()  

题目本身没什么难度,所以就不多说了~

emmmm…刚看到题目的时候,果然发现了我印象里没有的东西——yield。迅速查了资料,大概了解到,一般情况下,带有yield的函数不是一般的函数,而是一个生成器(generator)。
yield这个关键字的作用比较类似于return和print,均有输出/返回结果之意,next()表示依次返回迭代结果。

下面,暂且不说generator,先以一个简单的例子——裴波那契数列来说一说yield。

实例1:简单输出裴波那契数列的前n个数。

def fibo(max):
    n, a, b = 0, 0, 1
    while n < max:
         print b
         a, b = b, a + b
         n = n + 1

这样的写法属于常规操作,但是,函数的可复用性不高。因为fibo()函数没有返回值,其他函数无法获得该函数生成的数列。
这时我们会想到,为了提高函数的可复用性,我们不直接打印出数列,而是去返回一个List.
从而也就得到了下面这种做法。

实例2

def fibo(max):
    n, a, b = 0, 0, 1
    L = []
    while n < max:
         L.append(b)
         a, b = b, a + b
         n = n + 1
    return L

通过以上的改动,函数的可复用性大大提高,但是,该函数在运行中占用的内存会随着参数 max 的增大而增大,因此如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。

for i in range(1000):
    pass
# 会生成一个有1000个元素的List
for i in xrange(1000):
    pass
# 不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。 

利用 iterable 我们可以把 fibo() 函数改写为一个支持 iterable 的 class,这样也就有了下面的实例:

实例3

class Fibo(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 += 1
            return r
        raise StopIteration()


for n in Fibo(5):
    print n

Fibo 类通过 next() 函数不断返回数列的下一个数,内存占用始终为常数、

然而,

使用 class 改写的这个版本,代码远远没有实例1简洁。如果我们既要保持实例1的简洁性,又要获得 迭代效果,这时,yield 就派上用场了:

实例4

def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b 
        a, b = b, a + b 
        n = n + 1 

这时你就会发现,实例4与实例1的区别仅仅在于将中间的print换成了yield。


因此,简单来说,yield就是把一个普通函数变成了一个生成器。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

以上大致是今日所得,日后如果遇到相关问题,再对此文另行补充~

猜你喜欢

转载自blog.csdn.net/in_nocence/article/details/80243954