天域至尊 发表于 2022-2-10 17:01

【笔记】生成器yield简单探究

本帖最后由 天域至尊 于 2022-2-10 17:05 编辑

在python中,存在生成器的概念,生成器主要是由yield关键词实现的。
什么是生成器?生成器又有什么意义?我使用生成器的好处又是什么?

请大家试想一种场景,当你想要使用一个从 1-1000的int型列表。你需要如何制作这个列表?
大体思路如下:#声明函数名称,并提醒使用者返回类型为list
def create_list()->list:
    """
    该函数主要负责生成1-1000的列表
    """
    #初始化一个空白列表
    a=[]
    #初始化一个数字,用于后续自增
    num=0
    #进入循环,循环到1000时终止
    while num<1000:
      #数字自增1
      num=num+1
      #将该数字,增加到列表尾部
      a.append(num)
    #返回列表
    return a
大家可以看到,这是一种朴素的、简易的列表生成方式。

这种列表生成没有任何问题,除了时间和空间消耗较大以外,因为首先要做1000次循环,每次结果都要保存到列表(内存)中,然后整体再返回回来,给接下来的步骤使用。

单次1000次对整体性能影响不大,如果百万次、千万次,仅仅生成一个列表,就对程序的效率,产生了灾难级影响。
而这种花销给人一种愚蠢的、不可接受的、难以接受的印象。

那么,有没有什么想法可以解决这个问题呢?

出于朴素的想法,我们提出,是否可以让这个列表随用随生成呢?不要一口气生成,用一个生成一个,用完一个丢一个。
随后需求者提出了一个简单的需求:
   1.返回的结果是可以被for循环使用的,对使用者来说,完全可以当作一个列表使用。
   2.函数只能被调用一次。
   3.函数能够在列表中自动增加现在需要的值。
   4.函数能够把用过的数据自动删除。
   5.禁止使用多线程、多进程、任务队列等。
   6.要轻量级、好理解、好维护、代码量不超过20行。

开发者胖揍了一顿提出需求的人,然后回家了。
好,本文到此结束。

那是不可能的。这种简单的,朴素的需求,我们可以做到吗?
可以的,那就是生成器。

#声明函数名
def create_list():
    #初始化数字为零
    num=0
    #进入循环,循环到1000时终止
    while num<1000:
      #num自增1
      num=num+1
      #返回num的值,并暂停函数执行
      yield num
有心的同学,可能已经发现,这段代码和第一段基本没有差距,唯一的变动是两点:
1.没有初始化列表。
2.将return修改为了yield。

但是就两点简单的变动,完成了我们的上述的所有需求,样例程序:
#声明函数名
def create_list():
    #初始化数字为零
    num=0
    #进入循环,循环到1000时终止
    while num<1000:
      #num自增1
      num=num+1
      #返回num的值,并暂停函数执行
      yield num
      
#声明函数
a=create_list()
#循环遍历a中的所有值,并把值赋值给i
for i in a:
    #打印i的值
    print(i)
输出截图如下:

不可能,这不可能!这是怎么搞的,为什么会实现?
大家可以看看程序的执行流程图

中间可以发现,调用了yield以后,函数运行就被暂停了,等待下次迭代时,才继续运行,并且之前的状态也可以保存。

而我们所写的这个函数,就叫生成器,故名思意,一个个生成你想要的结果,用完即弃,大大减小了空间消耗。
同理生成器循环里也可以放很多操作步骤,这样整个程序的运行,就更加细粒度化,从而减小资源消耗。

既然学完了生成器,不如再去自学协程吧。

2014晴天 发表于 2022-2-21 16:39

就喜欢骚话多的,哈哈哈哈哈
页: [1]
查看完整版本: 【笔记】生成器yield简单探究