python 生成器(一):生成器基础(一)生成器函数
前言
实现相同功能,但却符合 Python 习惯的方式是,用生成器函数代替SentenceIterator 类。
示例 14-5 sentence_gen.py:使用生成器函数实现 Sentence 类
import re
import reprlib RE_WORD = re.compile('\w+') class Sentence: def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text) def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text) def __iter__(self):
for word in self.words: ➊
yield word ➋
return ➌
# 完成! ➍
❶ 迭代 self.words。
❷ 产出当前的 word。
❸ 这个 return 语句不是必要的;这个函数可以直接“落空”,自动返回。不管有没有 return 语句,生成器函数都不会抛出 StopIteration异常,而是在生成完全部值之后会直接退出。
❹ 不用再单独定义一个迭代器类!
在示例 14-4 定义的 Sentence 类中,__iter__ 方法调用SentenceIterator 类的构造方法创建一个迭代器并将其返回。
而在示例 14-5 中,迭代器其实是生成器对象,每次调用 __iter__ 方法都会自动创建,因为这里的 __iter__ 方法是生成器函数。
生成器函数的工作原理
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。
调用生成器函数时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。
简单的生成器函数
>>> def gen_123(): # ➊
... yield 1 # ➋
... yield 2
... yield 3
...
>>> gen_123 # doctest: +ELLIPSIS
<function gen_123 at 0x...> # ➌
>>> gen_123() # doctest: +ELLIPSIS
<generator object gen_123 at 0x...> # ➍
>>> for i in gen_123(): # ➎
... print(i)
1
2
3
>>> g = gen_123() # ➏
>>> next(g) # ➐
1
>>> next(g)
2
>>> next(g)
3
>>> next(g) # ➑
Traceback (most recent call last):
...
StopIteration
❶ 只要 Python 函数中包含关键字 yield,该函数就是生成器函数。
❷ 生成器函数的定义体中通常都有循环,不过这不是必要条件;这里我重复使用 3 次 yield。
❸ 仔细看,gen_123 是函数对象。
❹ 但是调用时,gen_123() 返回一个生成器对象。
❺ 生成器是迭代器,会生成传给 yield 关键字的表达式的值。
❻ 为了仔细检查,我们把生成器对象赋值给 g。
❼ 因为 g 是迭代器,所以调用 next(g) 会获取 yield 生成的下一个元素。
❽ 生成器函数的定义体执行完毕后,生成器对象会抛出StopIteration 异常。
生成器函数会创建一个生成器对象,包装生成器函数的定义体。
把生成器传给 next(...) 函数时,生成器函数会向前,执行函数定义体中的下一个 yield 语句,返回产出的值,并在函数定义体的当前位置暂停。
最终,函数的定义体返回时,外层的生成器对象会抛出StopIteration 异常——这一点与迭代器协议一致。
示例 14-6 使用 for 循环更清楚地说明了生成器函数定义体的执行过程。
>>> def gen_AB(): # ➊
... print('start')
... yield 'A' # ➋
... print('continue')
... yield 'B' # ➌
... print('end.') # ➍
...
>>> for c in gen_AB(): # ➎
... print('-->', c) # ➏
...
start ➐
--> A ➑
continue ➒
--> B ➓
end. ⓫
>>> ⓬
❶ 定义生成器函数的方式与普通的函数无异,只不过要使用 yield 关键字。
❷ 在 for 循环中第一次隐式调用 next() 函数时(序号➎),会打印'start',然后停在第一个 yield 语句,生成值 'A'。
❸ 在 for 循环中第二次隐式调用 next() 函数时,会打印'continue',然后停在第二个 yield 语句,生成值 'B'。
❹ 第三次调用 next() 函数时,会打印 'end.',然后到达函数定义体的末尾,导致生成器对象抛出 StopIteration 异常。
❺ 迭代时,for 机制的作用与 g = iter(gen_AB()) 一样,用于获取生成器对象,然后每次迭代时调用 next(g)。
❻ 循环块打印 --> 和 next(g) 返回的值。但是,生成器函数中的print 函数输出结果之后才会看到这个输出。
❼ 'start' 是生成器函数定义体中 print('start') 输出的结果。
❽ 生成器函数定义体中的 yield 'A' 语句会生成值 A,提供给 for 循环使用,而 A 会赋值给变量 c,最终输出 --> A。
❾ 第二次调用 next(g),继续迭代,生成器函数定义体中的代码由yield 'A' 前进到 yield 'B'。文本 continue 是由生成器函数定义体中的第二个 print 函数输出的。
❿ yield 'B' 语句生成值 B,提供给 for 循环使用,而 B 会赋值给变量 c,所以循环打印出 --> B。
⓫ 第三次调用 next(it),继续迭代,前进到生成器函数的末尾。文本end. 是由生成器函数定义体中的第三个 print 函数输出的。
到达生成器函数定义体的末尾时,生成器对象抛出 StopIteration 异常。for机制会捕获异常,因此循环终止时没有报错。
⓬ 现在,希望你已经知道示例 14-5 中 Sentence.__iter__ 方法的作用了:__iter__ 方法(指代 Sentence.__iter__ 方法)是生成器函数,调用时会构建一个实现了迭代器
接口的生成器对象,因此不用再定义 SentenceIterator 类了。
python 生成器(一):生成器基础(一)生成器函数的更多相关文章
- Python 基础 内置函数 迭代器与生成器
今天就来介绍一下内置函数和迭代器 .生成器相关的知识 一.内置函数:就是Python为我们提供的直接可以使用的函数. 简单介绍几个自己认为比较重要的 1.#1.eval函数:(可以把文件中每行中的数据 ...
- python基础之生成器,生成器函数,列表推导式
内容梗概: 1. 生成器和生成器函数. 2. 列表推导式. 1.生成器函数1.1 生成器函数. 就是把return换成yield def gen(): print("爽歪歪") y ...
- Python学习之路——迭代器、生成器、算法基础、正则
一.迭代器: 迭代器是访问集合元素的一种方式. 迭代器对象是从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. 另外,迭代 ...
- 十三. Python基础(13)--生成器进阶
十三. Python基础(13)--生成器进阶 1 ● send()方法 generator.send(value) Resumes the execution, and "sends&qu ...
- 十二. Python基础(12)--生成器
十二. Python基础(12)--生成器 1 ● 可迭代对象(iterable) An object capable of returning its members one at a time. ...
- python极简教程05:生成器和匿名函数
测试奇谭,BUG不见. 讲解之前,我先说说我的教程和网上其他教程的区别: 1 我分享的是我在工作中高频使用的场景,是精华内容: 2 我分享的是学习方法,亦或说,是指明你该学哪些.该重点掌握哪些内容: ...
- python基础(八)生成器,迭代器,装饰器,递归
生成器 在函数中使用yield关键字就会将一个普通的函数变成一个生成器(generator),普通的函数只能使用return来退出函数,而不执行return之后的代码.而生成器可以使用调用一个next ...
- python之三元表达式、列表推导、生成器表达式、递归、匿名函数、内置函数
目录 一 三元表达式 二 列表推到 三 生成器表达式 四 递归 五 匿名函数 六 内置函数 一.三元表达式 def max(x,y): return x if x>y else y print( ...
- python基础之生成器迭代器
1 生成器: 为什么要有生成器? 就拿列表来说吧,假如我们要创建一个list,这个list要求格式为:[1,4,9,16,25,36……]这么一直持续下去,直到有了一万个元素的时候为止.如果我们要创建 ...
随机推荐
- IOS 发布 程序截图问题
特别要注意那个有无状态栏时的像素要求 **注意:在截屏模拟器的时候,请把模拟器的Scale设置成100%(Window->Scale->100%) 开模拟器截图,运行每一个iOS型号,然后 ...
- 开源一款超实用的 Dubbo 测试工具,已用半年,感觉很有feel~
不知道你是否在工作中有遇到过类似情况: dubbo接口调试复杂,需要通过telnet命令或者通过consumer调用来触发. telnet语句参数格式复杂,每次编写都要小心谨慎,一旦出错又需重来. 复 ...
- vulstack红队评估(五)
一.环境搭建: ①根据作者公开的靶机信息整理 虚拟机密码: Win7: heart 123.com #本地管理员用户 sun\Administrator dc123.com #域管用户,改 ...
- 深入了解C#(TPL)之Parallel.ForEach异步
前言 最近在做项目过程中使用到了如题并行方法,当时还是有点犹豫不决,因为平常使用不多, 于是借助周末时间稍微深入了下,发现我用错了,故此做一详细记录,希望对也不是很了解的童鞋在看到本文此文后不要再犯和 ...
- Beta冲刺测试随笔
测试工作安排 人员安排: 余文锦,孙劼成,陈富杰,明锐,王彦杰,陈康杰:测试 杨铭海,张鑫宇测试用例的编写 测试工具选择和运用 本来计划Beta冲刺挑选人员进行测试相关的接触和学习并胜任测试工作,但是 ...
- 客户端软件GUI开发技术漫谈:原生与跨平台解决方案分析
原生开发应用开发 Microsoft阵营的 Winform WinForm是·Net开发平台中对Windows Form的一种称谓. 如果你想深入的美化UI,需要耗费很大的力气,对于目前主流的CSS样 ...
- 最短路之Floyd
#include<bits/stdc++.h>using namespace std;const int maxn = 300+10;int n,m,f[maxn][maxn],t; in ...
- (win7) 在IIS6.0 中配置项目
1.进入IIS管理器 右击“计算机”->管理->服务和应用程序->Internet信息服务(IIS)管理器 2.将项目加入IIS中 网站->右击“默认网站”->添加虚拟目 ...
- java语言基础-start
计算机基础 1.1 计算机以二进制存储数据 十进制数据转成二进制数据:使用除以2获取余数的方式 二进制数据转成十进制数据:使用8421编码的方式 1.2 字节 位(bit):一个数字0或者一个数字1, ...
- 每日一题 - 剑指 Offer 43. 1~n整数中1出现的次数
题目信息 时间: 2019-07-01 题目链接:Leetcode tag: 整除 取余 规律 递归 难易程度:中等 题目描述: 输入一个整数 n ,求1-n这n个整数的十进制表示中1出现的次数. 例 ...