Python之yield语法
生成器与yield
函数使用yield关键字可以定义生成器对象。生成器是一个函数。它生成一个值的序列,以便在迭代中使用,例如:
def countdown(n):
print('倒计时:%s' % n)
while n > 0:
yield n
n -= 1
return c = countdown(10)
如果调用该函数,就会发现其中的代码不会开始执行,相反它会返回一个生成器对象,接着该生成器对象就会在__next__()被调用时执行函数。
print(c.__next__())
print(c.__next__())
print(c.__next__())
调用__next__()时,生成器函数将开始执行语句,知道遇到yield语句为止。yield语句在函数执行停止的地方生成一个结果,直到再次调用next()。然后继续执行yield()之后的语句。通常不会在生成器上直接调用next()方法,而是通过for语句、sum()或一些消耗序列的其他操作使用生成器。例如:
for i in countdown(10):
print(i) a = sum(countdown(10))
print(a)
生成器函数完成的标志是返回或引发StopIteration异常,这标志着迭代的结束。如果生成器在完成时返回None以外的值都是不合法的。生成器使用时存在一个棘手的问题,即生成器函数仅被部分消耗,例如:
for n in countdown(10):
if n == 2:
break
print(n)
在这个例子中,通过调用break退出循环,而相关的生成器也没有全部完成。为了处理这种情况,生成器对象提供方法close()标识关闭。不再使用或删除生成器时,就会调用close()方法。通常不必手动调用close()方法,但也可以这么做。
在生成器函数内部,在yield语句上出现GeneratorExit异常时就会调用close()方法。也可以选择捕捉这个异常,以便执行清理操作
def countdown2(n):
print('倒计时:%s' % n)
try:
while n > 0:
yield n
n -= 1
except GeneratorExit:
print('GeneratorExit %s' % n) c = countdown2(2) print(next(c))
print(next(c))
del c
虽然可以捕捉GenratorExit异常,但对于生成器函数而言,使用yield语句处理异常并生成另一个输出值是不合法的。另外,如果程序当前正在对生成器进行迭代,不应该通过另一个的执行线程或从信号处理程序异步调用该生成器上的close()方法。
协程与yield表达式
在函数内, yield语句还可以作为表达式使用,出现在赋值运算符的右边,例如:
def receive():
print('Ready to receive')
while True:
n = yield
print('Got %s' % n)
以这种方式使用yield语句的函数称为协程,向函数发送值时函数将执行。它的行为也十分类似于生成器
r = receive()
r.__next__()
r.send(1)
在这个例子中,一开始调用__next__()是必不可少的,这样协程才能执行第一个yield表达式之前的语句。这时,协程会挂起,等待相关生成器对象r的send()方法给他发送一个值。
传递给send()的值由协程中的yield表达式返回。接收到值后,协程就会执行语句,直到遇到下一条yield语句。
在协程中需要调用next()这件事很容易被忽略,这经常称为错误出现的原因。因此,建议使用一个能够自动完成该步骤的装饰器来包装协程。
def coroution(func):
def start(*args, **kwargs):
g = func(*args, **kwargs)
g.__next__()
return g
return start # 使用这个装饰器就可以像下面这样编写和使用协程:
@coroution
def receive():
print('Ready to receive')
while True:
n = yield
print('Go %s' % n) r = receive()
r.send('hello world') # 无需初始调用.next()方法
协程一般会不断地执行下去,除非被显式关闭或者自己退出。关闭后如果继续给协程发送值就会引发StopIteration异常。正如前面关于生成器的内容中讲到的那样,close()操作将在协程内部引发GeneratorExit异常。
可以使用throw(exctype [, value [.tb]])方法在协程内部引发异常,其中exctype是指异常类型,value是指异常的值,而tb是指跟踪对象例如:
r.throw(RuntimeError, "You're hosed")
以这种方式引发的异常将在协程中当前执行的yield语句处出现。协程可以选择捕捉异常并以正确方式处理它们。使用throw()方法作为给协程的异步信号并不安全--永远都不应该通过单独的执行线程或信号处理程序调用这个方法。
如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值,例如:
def line_splitter(delimiter=None):
print("Ready to split")
result = None
while True:
line = yield result
result = line.split(delimiter) l = line_splitter(',')
l.__next__()
print(l.send("a,b,c"))
首个__next__()调用让协程向前执行到yield result,这将返回result的值None。在接下来的send()调用中,接收到的值被放在line中并拆分到result中。
send()方法的返回值就是传递给下一条yield语句的值。换句话说,send()方法的返回值来自下一个yield表达式,而不是接收send()传递的值的yield表达式。
如果协程返回值,需要小心处理使用throw()引发的异常。如果使用throw()在协程中引发一个异常,传递给协程中下一条yield语句的值将作为throw()
方法的结果返回。如果需要这个值却又忘记保存它,它就会消失不见。
yield from
yield from 是在Python3.3才出现的语法,后面需要加的是可迭代对象。
a = 'qwertt' def str_to_list():
yield from a def str_to_list2():
for i in a:
yield i print(list(str_to_list()))
print(list(str_to_list2()))
yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来,这样两者可以直接发送和产出值,还可以传入异常
而不用在位于中间的协程中添加大量处理异常的样板代码。
双向通道: 调用方通过send()直接发送信息给子生成器,而子生成器yield的值,也直接返回给调用方
从Python 3.5开始引入了新的语法 async 和 await ,而await替代的就是yield from
Python之yield语法的更多相关文章
- Python关键字yield的解释(stackoverflow)
3.1. 提问者的问题 Python关键字yield的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码: def node._get_child_candidates(self, dista ...
- Python基础:语法基础(3)
本篇主要介绍Python中一些基础语法,其中包括:标识符.关键字.常量.变量.表达式.语句.注释.模块和包等内容. 1. 标识符和关键字 1.1 标识符 标识符是变量.常量.函数.属性.类.模块和包等 ...
- python 关键字yield解析
python 关键字yield解析 yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator.y ...
- 一. Python基础(1)--语法
一. Python基础(1)--语法 1. 应用程序 1.1 什么是计算机(Computer)? 组成 ①运算器 arithmetic unit; ※ Arithmetic unit and cont ...
- python语句和语法
python语句和语法 python程序结构: 1.程序由模块构成. 2.模块包含语句. 3.语句包含表达式. 4.表达式建立并处理对象. python的语法实质上是有语句和表达式组成的.表达式处理对 ...
- python 关键字yield
问题 Python 关键字 yield 的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码: def node._get_child_candidates(self, distance, m ...
- Python的基础语法(二)
0. 前言 接着上一篇博客的内容,我将继续介绍Python相关的语法.部分篇章可能不只是简单的语法,但是对初学者很有帮助,也建议读懂. 1. 表达式 由数字.符号.括号.变量等组成的组合. 算术表达式 ...
- 六. Python基础(6)--语法
六. Python基础(6)--语法 1 ● Python3中, Unicode转字节的方法 print(bytes("李泉", encoding = 'utf-8')) prin ...
- 五. Python基础(5)--语法
五. Python基础(5)--语法 1 ● break结束的是它所在的循环体, continue是让它所在的循环体继续循环 # 打印: 1 10 2 10 3 10 4 10 5 10 6 10 7 ...
随机推荐
- PAT甲级题分类汇编——排序
本文为PAT甲级分类汇编系列文章. 排序题,就是以排序算法为主的题.纯排序,用 std::sort 就能解决的那种,20分都算不上,只能放在乙级,甲级的排序题要么是排序的规则复杂,要么是排完序还要做点 ...
- Java中final与C++中const的关系
Java中的final有三种主要用法: (1)修饰变量: final变量是不可改变的,但它的值可以在运行时刻初始化,也可以在编译时刻初始化,甚至可以放在构造函数中初始化,而不必在声明的时候初始化,所以 ...
- unittest之makeSuite\testload\discover及测试报告teseReport
转载:http://www.cnblogs.com/sunny0/p/7771089.html 测试套件suite除了使用addTest以外,还有使用操作起来更更简便的makeSuite\testlo ...
- centos可选的安装类型
Desktop :基本的桌面系统,包括常用的桌面软件,如文档查看工具. Minimal Desktop :基本的桌面系统,包含的软件更少. Minimal :基本的系统,不含有任何可选的软件包. Ba ...
- shell 学习笔记7-shell-函数
一.函数 1.什么是shell函数 把相同程序段定义成函数,可以减少整个程序的代码量,提升开发效率 增加程序的可读性,易读性,提升管理效率 可以失效程序功能模块化,使程序具备可移植性 其实linux系 ...
- 天梯赛 L3-002. 堆栈
思路:这里的线段树维护一个区间里面出现数的个数,对于Pop,push单点更新一下就好. #include<stdio.h> #include<iostream> #includ ...
- SaltStack实现动态文件分发,支持脚本换行,中文乱码
场景:将动态脚本分发到各个机器的指定目录下 说明:使用SaltStack的 file.managed file.managed 里面可以定义内容的几种方式 - source: - contents: ...
- 3_PHP表达式_1_常量
以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. PHP常量分为自定义常量与预定义常量. 1.自定义常量 在使用前必须先定义,PHP的define()函数专门用于定 ...
- activemq BytesMessage || TextMessage
需求:使用 python 程序向 activemq 的主题推送数据,默认推送的数据类型是 BytesMessage,java 程序那边接收较为麻烦,改为推送 TextMessage 类型的数据 解决方 ...
- robot framework 的关键字Continue For Loop 用法
Continue For Loop关键字就是python的continue的意思,跳出本层循环,继续执行下一个循环. 我先举个栗子: :FOR ${index} IN RANGE 5 ...