【Python】深入浅出学习Python的yield和generator
背景
之前走马观花接触过Python协程的概念,这两天和一个同事聊到了协程,死活想不起来曾经看过的东西,就记得一个yield,概念不清;
所以想捋一捋相关的东西,此篇作为学习的记录。
Generator
generator(生成器)保存的是算法,可以理解为一个特殊的函数,有迭代的属性(可迭代的对象都有一个__next()__成员方法)
可以被用作控制循环的迭代行为,做到一边循环一边计算;特点是只有被调用的的时候才会生成,能做到不多占用系统的资源。
在我们日常工作过程中接触最多的generator可能就是Python3.X中的range函数,我们来看一下它和Python2.x中range的用法区别:
# python2
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(range(10))
<type 'list'>
# python3
>>> range(10)
range(0, 10)
>>> type(range(10))
<class 'range'>
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
如示例,Python2 是直接生成的列表list,而Python3中调用range(10)实际上是生成了一个range类,需要转换才能生成list。
Python2这样直接生成列表的机制,在实际使用中容量可能会受到内存的限制。而且如果创建一个包含100万个元素的列表,而我们又仅仅只需要访问前面几个元素,那绝大多数的内存占用就会白白浪费。所以Python3的开发者们才会在这一个小小的函数上花精力。
Generator的使用
创建generator:列表生成式
创建generator方法有很多,最直接最简单的方法就是使用 列表生成式:
>>> L = [x * 2 for x in range(5)]
>>> L
[0, 2, 4, 6, 8]
>>> G = (x * 2 for x in range(5))
>>> G
<generator object <genexpr> at 0x000000000309DD58>
如上例,只要把一个列表生成式的[]改成(),就创建了一个generator
我们可以通过next()函数获得generator的返回值
>>> next(G)
0
>>> next(G)
2
>>> next(G)
4
>>> next(G)
6
>>> next(G)
8
>>> next(G)
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
next(G)
StopIteration
每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
当然,这个只是测试,正确的使用方式是使用for循环,在for循环中,会自动遵循迭代规则,每次调用next()函数,而且不需要关心StopIteration的错误。
>>> for i in G:
print(i)
0
2
4
6
8
创建generator: 直接定义生成器函数
# 普通函数
def commom_func(max):
print("create counter")
counter = 0
while counter < max:
print(counter)
print('counter increase')
counter += 1
# 生成器函数
def yield_func(max):
print("create counter")
counter = 0
while counter < max:
yield counter
print('counter increase')
counter += 1
# 生成器函数调用
if __name__ == '__main__':
num = yield_func(5)
print(next(num))
print(next(num))
print(next(num))
---
# 生成器函数调用输出
create counter
0
counter increase
1
counter increase
2
从上面这个例子可以看出以下几点:
- 在yield_func函数中出现了关键字yield,这个函数返回一个生成器(通过第一行输出可以看出来),用来产生连续的n值,生成器每次只产生一个结果值
- 在创造生成器实例的时候,只需要像普通函数一样调用就可以,但是这个调用却不会执行这个函数
next()函数将生成器对象作为自己的参数,在第一次调用的时候,他执行了yield_func函数到yield语句,返回产生的值0- 我们重复的调用next()函数,每次他都会从上次被挂起的地方开始执行,直到再次遇到了yield关键字
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
下面是一个更直观的例子
def step_test():
print('step 1')
yield 1
print('step 2')
yield 2
print('step 3')
yield 3
调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:
>>> test = step_test()
>>> next(test)
step 1
1
>>> next(test)
step 2
2
>>> next(test)
step 3
3
总结
- generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator
- 对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
- 普通函数调用直接返回结果,generator函数的“调用”实际返回一个generator对象:
>>> step_test()
<generator object step_test at 0x0000000001DE5B48>
【Python】深入浅出学习Python的yield和generator的更多相关文章
- 推荐3个Python初学者学习Python案例
回复资料,获取最新的Python的资料.想学习Python可以加微信回复报名. 希望今天的分享3个小案例,对你学习Python有帮助 Python 九九乘法表 以下实例演示了如何实现九九乘法表: 实例 ...
- python初步学习-python函数(一)
python 函数 函数是组织好的,可重复使用的,用来实现单一或者相关联功能的代码段. 函数能提高应用的模块性和代码的重复利用率. 函数定义 python中函数定义有一些简单的规则: 函数代码块以de ...
- python初步学习-python函数 (二)
几个特殊的函数(待补充) python是支持多种范型的语言,可以进行所谓函数式编程,其突出体现在有这么几个函数: filter.map.reduce.lambda.yield lambda >& ...
- Python基础学习-Python中最常见括号()、[]、{}的区别
Python中最常见括号的区别: 在Python语言中最常见的括号有三种,分别是:小括号().中括号[].花括号{}:其作用也不相同,分别用来代表不同的Python基本内置数据类型. Python中的 ...
- python初步学习-Python模块之 re
re 正则表达式 python正则表达式在线检验网站 python re正则表达式语法 匹配字符 语法 解释 表达式 匹配实例 . 匹配任意除"\n"以外的任何字符 a.c abc ...
- python初步学习-python 模块之 json
json 模块 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写.一般API返回的数据大多是 JSON.XML,如果返回JSON的话,将获取 ...
- python初步学习-python模块之 os
os os 模块在运维工作中是很常用的一个模块.通过os模块调用系统命令.os模块可以跨平台使用. 在 import os的时候,建议使用import os而非from os import *.这样可 ...
- python初步学习-python模块之 logging
logging 许多应用程序中都会有日志模块,用于记录系统在运行过程中的一些关键信息,以便于对系统的运行状况进行跟踪.在python中,我们不需要第三方的日志组件,python为我们提供了简单易用.且 ...
- python初步学习-python文件操作
文件 文件,在python中,他是一种类型的对象,类似前面已经学过的其他数据类型,包括文本的.图片的.音频的.视频的等等,还有不少没见过的扩展名的.事实上,在linux操作系统中,所有的东西都被保存到 ...
随机推荐
- httprunner上传文件multipart/form-data
Content-Type = multipart/form-data#上传文件 Rquest Payload ------WebKitFormBoundarymAyGmnyhpf3UBdec C ...
- 我眼中的DevOps(转)
过去一年以来,一批来自欧美的.不墨守陈规的系统管理员和开发人员一直在谈论一个新概念:DevOps.DevOps 就是开发(Development)和运维(Operations)这两个领域的合并.(如 ...
- IBM Java 7 新特性和在 WAS 8.5 中的配置【转载】
IBM Java 7新特性以及在WAS V8.5 中的安装与版本切换 简介: 本文介绍了 IBM Java 7 的基本新特性以及 IBM 特有的新特性,并详细的介绍和分析了 JVM 所采用的新的垃圾回 ...
- Java栈之链式栈存储结构实现
一.链栈 采用单链表来保存栈中所有元素,这种链式结构的栈称为链栈. 二.栈的链式存储结构实现 package com.ietree.basic.datastructure.stack; /** * 链 ...
- (转)CentOs7.3 搭建 RabbitMQ 3.6 Cluster 集群服务与使用
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.ActionScript.XMPP.STO ...
- opencv:vs2015添加了包含目录依然无法打开‘opencv2/core/core.hpp’ 解决方法
安装环境 win10 vs2015 出错和改错 按网上的教程,配置好opencv后,包括已经把以下内容添加到'包含目录'了: E:\openCV\opencv\build\include E:\ope ...
- 设备驱动与控制器 I/O
控制器是对硬件发起控制命令,负责给系统提供接口,想要正常使用该硬件功能系统中必须安装相应驱动 I/O设备 cpu和存储器并不是操作系统唯一需要管理的资源,I/O设备也是非常重要的一环. I/O设备一般 ...
- python全栈开发从入门到放弃之socket并发编程多线程GIL
一 介绍 ''' 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple nati ...
- Tornado 自定义Form,session实现方法
一. 自定义Tornado 验证模块 我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单 ...
- 使用自签名SSL证书配置HTTPS,解决浏览器提示不安全警告
项目测试过程中需要将应用从HTTP升级到HTTPS,浏览了网上一些帖子,参考<WebLogic11g-单双向SSL配置(以Springside3为例)>一文使用openssl工具来自建CA ...