python3:生成器yield深度解析

版权声明:转载 或者复制请标注来源 https://blog.csdn.net/qq_34979346/article/details/83896015

生成器这个章节尤其的重要,我们以后的协程的部分要用到这个知识点.
什么是生成器函数呢?
定义为:
只要方法里有 yield 这个关键字 代表不是普通的函数,就可以认为是生成器函数 .

怎么就不普通了,咱们和普通的比较下 ,代码如下:

def gen_func():
    yield  1

def func():
    return  1

print(gen_func(),func())  
#打印结果 
#<generator object gen_func at 0x000000000220AE60> 1

我们可以发现 gen_func() 返回的是一个对象,并不是1.
func()返回的是1 .

有的小伙伴该说了,那我们怎么去访问生成器里面的1 呢?
这个是个好问题,我们访问对象里的值一定要用到前面的知识,迭代器和迭代对象.
PS:看来知识都是关联的,要想遇到什么就学什么,绝对没有思路.

我也不做多解释,用代码解释来的直接 :

from collections import Iterable, Iterator


def gen_func():
    yield  1

def func():
    return  1

print(gen_func(),func())

print(isinstance(gen_func(),Iterable))  #True
print(isinstance(gen_func(),Iterator))   #True
  
print(next(gen_func()))   # 1  

借用小岳岳的一句话“这么神奇呀,生成器也是迭代器”
有了这个我们就可以放心用for 循环进行输出. 这太方便了吧.

那有较真的小伙伴该说了,你这不是瞎胡搞吗,本来直接return 个返回值
直接输出就行了,你非得再绕一大圈 然后再输入,你感觉有意思吗?

好像他说的也没有错呀,but 有个场景,我需要return 两次甚至更多,如何做呢
按照你的方法,要更多return 呗, 好我就让你心服口服,看看代码吧

def func():`在这里插入代码片`
    return  1
    return  2

print(func())
#打印结果: 1

return 2 并没有返回,为什么呢, 因为在return 1 的时候已经断掉了,后边的代码不会执行.

小伙伴们该说了,这样是行不通,那有什么办法吗 ? 当然离不开这节的主题,答案是生成器

请看下边的代码:

def gen_func():
    yield  1
    yield  2
    yield  "Andy"

print(gen_func())

for  i  in gen_func():
    print(i)

#打印结果   
#<generator object gen_func at 0x000000000288F2B0>
#1
#2
#Andy

都打印出来了, 功能强爆了.
稍微解释下:
当我们用for 循环的时候,会调用 第一个 next() 打印出1,然后在next()打印出2
一直循环到报 StopIteration 异常结束.
由于我们调用next()会返回一个值,不调用不会往下返回值,这个特性很重要,
官方的叫法是惰性求值 .

为了明白惰性求值的好处, 我来举个例子 ,

经典斐波拉契
斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377

这个数列从第3项开始,每一项都等于前两项之和。

用普通的方法,来 求10位之和

def func(index):
    if index<=2:
        return  1
    else:
        return func(index-1)+func(index-2)

print(func(10)) #  55

用普通的方法,也可用实现,但是我们有个问题就是 想打印它计算过程,你怎么搞?

用普通的方法我们可以这么写

def func2(index):
    a=0
    b=1
    n=0
    list_num=[]
    while n<index:
        list_num.append(b)
        a,b=b,a+b
        n+=1
    return list_num

print(func2(10))
#打印结果    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

上边的 a,b=b,a+b 就相当于 a=b , b=a+b 这也是循环的递增方式.

有个问题,我们知道用list 有个缺点就是 性能低,如果index 很大的时候,不要用print,
这是血的教训 ,我刚刚就重启了. 还好博客的内容还在. 当index 是上千万的时候,也不要调用方法
,非常占内存,你的机器同样也会死机。

我们开始用 生成器的方式进行访问如下边

def gen_func(index):
    a=0
    b=1
    n=0

    while n<index:
        a,b=b,a+b
        n+=1
        yield b

for i in gen_func(10):
    print(i)
    #打印结果  
 1
2
3
5
8
13
21
34
55
89

我们已经实现了打印过程,为什么它可以使用index值为成千上万的呢,这还是离不开生成器的惰性机制,
当调用 yield 的时候,会把数值存在生成器里面,直到循环结束.
next()的时候,调用一下,不调用就不输出.

更多的功能我会在一节介绍,请关注

猜你喜欢

转载自blog.csdn.net/qq_34979346/article/details/83896015