仿古印章生成器在线_Python 的关键字 yield 有哪些用法和用途?

yield的用法有以下四种常见情况:一种是生成器,另一种是用于定义上下文管理器,第三种是协同过程,第四种是使用从形成yield,用于消费子生成器和传递消息这四种用法实际上是由产量的停顿特征衍生而来的。也就是说,当程序运行到yield所在的位置时,result = yield expr,yield expr将生成的值返回给调用生成器的调用方,然后暂停,等待调用方再次激活并恢复程序的执行。然而,根据恢复程序使用的方法,产量表达式的结果值结果也会相应地改变。如果__next()__用于调用,则产量表达式的值结果为“无”;;如果send()用于调用,则产量表达式的值结果是通过send函数传递的值下面是一个正式文档引入产量表达式的例子:

执行第一个next(生成器),即生成器是预激活的。生成器开始执行,打印开始...字符串,当执行到value = (yield value)的位置时,首先调用yield value来生成数字1,然后生成器在yield的位置暂停当

next调用第二个next(生成器)时,生成器恢复执行。因为next()用于调用生成器函数,所以该值将变为None,所以当生成器函数继续产生值时,它将向解释器返回None值,然后再次暂停

然后使用send(2)方法继续调用生成器。value接收传入的数字2,继续执行value =(屈服值),将数字2返回给解释器,并暂停

之后,解释器通过throw(TypeError,“spam”)方法再次调用,生成器恢复执行并抛出异常。生成器捕获异常并将异常类型错误(“垃圾邮件”)分配给变量值。然后程序再次执行到value =(屈服值),并将类型错误(“垃圾邮件”)返回给解释器

最后,程序调用close()方法,在生成器函数的位置抛出GeneratorExit,抛出异常,生成器正常退出,最后执行对应于最外层try语句的finally分支,并打印出Clean up

发生器

不是偶然的,你首先遇到的产量必须在发生器函数中生成器是一个连续生成数字或其他类型值的函数,可以通过for循环或next()函数逐个调用这里应该强调的是,生成器包含一个未赋值的产量表达式。因此,以下两种形式是等价的[2):

定义整数_ 1():对于输入范围(4):输出1+1定义整数_ 2():对于输入范围(4):值=输出1+1

这里强调第二种形式的原因是为了在理解通过send()方法发送的值时更好地理解输出同时,可以更正确地解释调用生成器返回的值是yield关键字右侧的表达式i+1的值,而不是yield表达式本身的结果值。

让我们试着打电话:

>。>;>;对于整数1()中的n:...打印(n)...1234>。>;>;对于整数_ 2()中的n:...打印(n)...1234

上下文管理器

在Python的contexlib模块中与@contextmanager decorator协作,yield也可用于定义上下文管理器。以下是Python Tricks [3中的一个示例:

from contextlibimportcontextmanager @ contextmanagerdfmanaged _ file(name):try:f = open(name,W ')yield f finally:f . close()

上面由decorator和yield关键字定义的上下文管理器相当于以下类的方法定义:

class managed file:def _ _ init _ _(self,name):self . name = name def _ _ enter _ _(self):self . file = open>;>;以ManagedFile('hello.txt ')作为f:...写(‘你好,世界!)...f . write(‘拜拜’)& gt。>;>;将managed_file('hello.txt ')作为f:...写(‘你好,世界!)...f . write(‘bye now’)

association

association的概念充满美感,非常符合人们的商业模式,想要完全掌握还需要花费一些时间然而,这些努力是值得的,因为有时候多线程比协调带来更多的麻烦。下面是一个仅在Python Cookbook [4中使用产量表达式编写的协同示例:

来自collectionsimport deque #两个简单生成器函数递减计数(n):当n > 0时:打印(' T-减号',n)产量n -= 1打印(' Blastoff!')延迟计数(n): x = 0,而x & ltn:打印(“向上计数”,x)产生x+= 1分类任务计划程序:def __init__(自我):自我。_ task _ queue = dequee()def new _ task(self,task):' ' '将新启动的任务接纳到计划程序' ' ' self中。_ task _ queue . append(task)def Run(self):' ' '运行,直到自我运行时不再有任务' ' '。_task_queue: task = self。_task_queue.popleft()尝试:#运行直到下一个收益语句下一个(任务)自身。_task_queue.append(task)除了StopIteration之外:#生成器不再执行传递#示例use schedule = task scheduler()schedule . new _ task(倒计时(2)) schedule.new _ task(计数(5)) schedule.run ()

运行上述脚本并获得以下输出:

t-2 count up 0t-1 count up 1 blast off!递增计数2递增计数3递增计数4

递减计数和递增计数交替执行。当主程序执行递减函数的产量表达式时,它将在暂停后重新加入队列。然后,从队列中取出计数任务,并在表示产量表达式的地方暂停执行。挂起的协调例程也附加到队列中,然后从队列中取出最左边的任务倒计时继续执行。重复上述过程,直到队列为空上面的协议

可以重写为

导入asyncioasync defcount down (n):而n >则通过使用Python3.7中的asynco库来实现。0:打印(' T-减号',n)等待asyncio.sleep(0) n -= 1打印(' Blastoff!')异步延迟计数(n): x = 0,而x & ltn:print(‘计数’,x)wait asyncio . sleep(0)x+= 1 sync def main():wait asyncio . gather(倒计时(2),COUNTUP (5)) asyncio。RUN (MAIN ())

可以看出,用Asyncio库编写的协同示例比用yield编写的要优雅、简单和易于理解得多。说实话,屈服于有点令人困惑。来自的Yield在协作中使用得更频繁,而wait关键字的引入将大大降低来自使用的yield的频率。一方面,来自的Yield可以迭代地消耗生成器,另一方面,它可以建立双向通道,允许调用方和子生成器方便地通信,并自动处理异常和接收子生成器返回的值。以下是Python Cookbook中扩展嵌套序列[5的示例:集合中的

。abcimportable defflap (items,ignore _ type =(str,bytes)):对于x in items: if isinstance(x,Iterable)和not isinstance(x,ignore _ type):yield from flat(x)否则:yield xitems = [1,2,[3,4,[5,6],7],8]# products 1 2 3 4 5 6 7 8 for x in flap(items):print(x)

而yield from用于建立双向通道。请参考Fluent Python中的示例[6]。此处不再详细解释此代码:

# beginyield _ from _ averageformcollectionimportnamedtupleresult = namedtuple(' Result ',' count average')#子generatordef averager():total = 0.0 count = 0 average = None而True: term = yield如果term为None:break total+= term count+= 1 average = total/count返回结果(count,average)#委托generatordef grouper(results,key):而True:results[关键字]= averager的yield a . k . caller def main(data):results = { } for key,value in data . items():group = grouper(results,key)next(group)for value in values:group . send(value)group . send(None)report(results)# output report def report(results):for key,results in sorted(results . items()):group,unit = key . split(;) )打印(f“{ result . count:2 } { group:5 }平均{result.average:.2f}{unit}”)数据= { '女孩;“公斤”:[40.9、38.5、44.3、42.2、45.2、41.7、44.5、38.0、40.6、44.5],“女孩;' m': [1.6,1.51,1.4,1.3,1.41,1.39,1.33,1.46,1.45,1.43],'男孩;' kg': [39.0,40.8,43.2,40.8,43.1,38.6,41.4,40.6,36.3],'男孩;' M': [1.38、1.5、1.32、1.25、1.37、1.48、1.25、1.49、1.46],}如果_ _ name _ _ = = ' _ _ main _ _ ':main(data)

可能会让精通Python的程序员感到审美愉悦。但是对我这个刚刚开始的人来说,除了让我感觉很美的生成器语法,其他语法让我理解得非常费解。幸运的是,asyncio库集成到了Python的标准库中。关键字async和wait的引入将使我们在编写协调程序时使用产量和产量。然而,产量在Python中是一个非常特殊的关键字,花时间掌握它是值得的。

大家都在看

相关专题