我是靠谱客的博主 含蓄棉花糖,最近开发中收集的这篇文章主要介绍Python学习笔记16:生成器Python学习笔记16:生成器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Python学习笔记16:生成器

在前文Python学习笔记15:推导式的结尾我们已经引出了Python中的另一项特性:生成器。

要说明的是生成器和推导式在写法上是极为相似的,除了生成器是用()来包裹以外。但实际上,他们有很大不同。

基本概念

我们现在看一个简单的例子:

import requests
urls = ("https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448",
        "https://www.runoob.com/w3cnote/python-spider-intro.html",
        "https://www.runoob.com/w3cnote/secure-wordpress-nginx.html",
        "https://cn.python-requests.org/zh_CN/latest/")
resps = []
for url in urls:
    resp = requests.get(url)
    resps.append(resp)
for resp in resps:
    print(len(resp.text))

在这个例子中,我们读取一个url列表,然后用requests模块获取其内容,然后输出内容的长度。

我们现在改写为推导式:

import requests
urls = ("https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448",
        "https://www.runoob.com/w3cnote/python-spider-intro.html",
        "https://www.runoob.com/w3cnote/secure-wordpress-nginx.html",
        "https://cn.python-requests.org/zh_CN/latest/")
resps = [requests.get(url) for url in urls]
for resp in resps:
    print(len(resp.text))

如果你注意输出的话,就不难发现,程序需要等待一会,然后才会一股脑输出所有结果。

这也不难理解,因为输出是要等到推导式处理完所有url后才会开始,那如果我们把推导式换成生成器呢?

import requests
urls = ("https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448",
        "https://www.runoob.com/w3cnote/python-spider-intro.html",
        "https://www.runoob.com/w3cnote/secure-wordpress-nginx.html",
        "https://cn.python-requests.org/zh_CN/latest/")
for resp in (requests.get(url) for url in urls):
    print(len(resp.text))

注意,生成器必须放在一个循环语句中,所以这里并没有采用复制给resps变量的做法。

我们可以注意到,此时结果输出是依次进行,中间会有或长或短的间隔,这是因为生成器的特性与推导式大为不同。

优缺点

如果你接触过安卓开发,可能会知道安卓开发中的gallery组件,也就是我们日常使用手机中很常见的预览图片时候左右滑动的那个,这个组件的实现其实和Python中的生成器异曲同工。

要知道,在很多时候我们的程序依然要考虑硬件性能,比如加载巨量数据或者图片等很占用资源的内容。而安卓平台的gallery组件就是如此,因为图片加载是很浪费内存的,你不可能把一组图片全部都加载入内存,一来浪费内存,二来也没有必要,毕竟用户一次只能看到一张图片。所以安卓给gallery加入了这样的特性:一次只会把当前图片和前后两张图片加载入内存,这样用户在左右滑动的时候几乎不会感觉到加载延迟,但又极大节省了不必要的资源消耗。

而Python的生成器和gallery的理念完全一致,可以把它看成一个Python版的gallery,当我们用循环或别的方式获取这个生成器的某一个元素时,生成器才会实时生成这个元素,当你不再访问这个元素的时候,它会立即抛弃。

所以在上边这个例子中,我们是一边获取url一边读取网络内容,然后进入以此往复。

我们可以看到生成器具有以下优点:

  • 节约系统资源。
  • 可以将集中性的耗时操作切分为小段,避免长时间没有响应。

但显然也不是没有缺点的,如果我们需要一次性获取多个元素并依照这多个元素来进行处理,就显得很不方便了。

生成器函数

除了直接把生成器作为表达式使用,我们还可以将其包装成函数。

import requests
urls = ("https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448",
        "https://www.runoob.com/w3cnote/python-spider-intro.html",
        "https://www.runoob.com/w3cnote/secure-wordpress-nginx.html",
        "https://cn.python-requests.org/zh_CN/latest/")


def getUrlRes(urls: tuple):
    for url in urls:
        yield requests.get(url)

for resp in getUrlRes(urls):
    print(len(resp.text))

在上边这个例子中,我们把生成器包装成了一个函数getUrlRes,这很有用,我们屏蔽了生成器的实现细节,其它人只要使用就可以了。

应该注意到,我们在生成器里返回值的时候使用的是yield而非return。这不难理解,如果使用return,程序会立即返回,getUrlRes也不会再次执行,而yield将告诉解释器,这里是一个生成器,在外部程序获取一个值的同时,生成器函数会挂起,直到外部程序进入下一次循环/遍历,此时生成器会从挂起的地方再次运行,并返回下一个值。

好了,关于生成器的话题就到这里了,接下来的一段时间我会探究一下Python中面向对象的部分,比照其它语言,挖掘一下前边没有深入的部分。在这部分梳理完毕后,我会重新阅读一遍《Head First 设计模式》,并用Python和类图的形式整理一遍设计模式的内容。

谢谢阅读。

最后

以上就是含蓄棉花糖为你收集整理的Python学习笔记16:生成器Python学习笔记16:生成器的全部内容,希望文章能够帮你解决Python学习笔记16:生成器Python学习笔记16:生成器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部