当前位置: 首页 > news >正文

75、Python之函数式编程:生成器的核心方法及更多使用场景

引言

Python中的函数式编程,依托生成器,可以实现惰性求值的特性。但是,生成器其实还可以有更多的使用场景。本文就聚焦生成器,再次聊聊生成器中的主要方法以及更多的使用场景。

本文的主要内容有:

1、生成器的核心方法

2、生成器的使用场景

生成器的核心方法

首先还是来看下生成器的定义:

7633e99edda71758dccc79f97e8c511b.jpeg

生成器类中,主要用到的有这几个方法:

1、__next__()方法,用于获取生成器的下一个元素,如果没有更多元素了,则会抛出StopIteration异常。

2、send()方法,用于像生成器对象发送一个值,从而实现双向通信的场景。

3、throw()方法,用于向生成器内部引发一个异常,生成器内部可以捕获并处理该异常。

4、close()方法,用于关闭一个生成器对象。

接下来,我们通过代码实例演示一下这几个方法的使用。

def generator():while True:try:msg = yield '等待接收新的消息...'if msg:print(f'收到新消息: {msg}')if msg.lower() == 'exit':breakexcept ValueError:yield '发生异常,通信结束'yield '通信结束'gen = generator()
# __next__()
print(gen.__next__())
# send()发送一个值
print(gen.send('hello python'))
# 发送一个异常
print(gen.throw(ValueError))
# __next__()
print(gen.__next__())
print(gen.close())
# 发送exit消息可以终止
print(gen.send('exit'))
# 也可以手动调用close()
# 再次调用__next__()就会抛StopIteration异常了
gen.__next__()

执行结果:

fa3d28710cb261db35090aebbf89a94e.jpeg

简单总结一下这几个方法的使用:

1、__next__()方法,前面已经介绍过,会获取到yield表达式右侧的值,如果生成器已经被耗尽(没有更多的值了),则抛出StopIteration异常,等价于内置函数next()。

2、send()方法,用于向生成器发送一个值,并使生成器继续执行下一个yield表达式。发送的值会被赋值给一个yield表达式的左侧。与__next__()方法不同,send()方法可以在生成器与调用者之间实现双向通信。

3、throw()方法,用于向生成器内部引发一个异常,生成器可以在内部捕获这个异常,并处理它。如果生成器内部没有捕获这个异常,它将传播到调用者,并终止生成器。

4、close()方法,用于关闭一个生成器对象,之后,将不能对该生成器执行任何方法,否则均会抛出StopIteration异常。

生成器的使用场景

了解了生成器中的核心方法,接下来看一下更多的应用生成器的场景。

1、基本的协程的场景

协程是一种可以在执行过程中暂停和恢复的子程序,基于生成器自动阻塞的特性,以及send()方法可以实现的双向通信功能,可以利用生成器实现基本的协程的功能,适用于异步编程和多任务的写作。

这里暂时不进行代码的演示了,后面会在并发编程中详细展开。

2、状态机

基于生成器可以实现一个简单的状态机的功能,每次可以使用send()方法来改变生成器的状态。可以通过代码来看一个简单的状态机的模拟。

直接看代码:

def state_machine():state = 'PLAN'while True:if state == 'PLAN':state = yield 'PLAN PHASE'elif state == 'DO':state = yield 'DO PHASE'elif state == 'CHECK':state = yield 'CHECK PHASE'elif state == 'ACT':state = yield 'ACT PHASE'# 模拟PDCA/戴明环
sm = state_machine()
print(next(sm))
print(sm.send('DO'))
print(sm.send('CHECK'))
print(sm.send('ACT'))
print(sm.send('PLAN'))

执行结果:

1deb3bf0373d303cc853605100e83088.jpeg

3、实时数据处理

生成器可以用于处理实时输入的数据,例如传感器监测数据、网络日志等,通过send()方法实现实时数据的传入及处理。

以一个实时计算平均值的示例作为演示:

def calculate_avg():total = 0count = 0avg = Nonewhile True:num = yield avgtotal += numcount += 1avg = total / countprint(f'已接收到{count}个数字,总和:{total},平均值:{avg}')averager = calculate_avg()
# 启动生成器,首次返回None
print(averager.__next__())
# 模拟实时传值并计算
print(averager.send(10))
print(averager.send(15))
print(averager.send(25))

执行结果:

00ede24a3193783bd993913acb5355d0.jpeg
其实代码逻辑很简单,只要能够理解生成器的基本执行原理即可,这里重点回顾一下:

next()之后会阻塞在yield表达式,send()会从上次阻塞点开始执行,首先会把传入的值赋值给yield表达式的左侧,然后一直执行到yield表达式返回结果,并阻塞,等待下次执行。

4、消息的传递与处理

由于生成器的send()双向通信的功能,以及实现基本的协程的功能,所以,生成器可以用于实现简单的消息处理系统。

5、用户输入处理

生成器可以用来处理用户的输入,比如前面例子中,根据用户的输入指令决定是只打印输出,还是终止生成器。

以上,就是本文的全部内容了。

总结

简单总结一下,本文结合生成器的定义,简单介绍了__next__()方法、send()方法、throw()方法,以及close()方法的使用。基于send()方法可以实现生成器与调用者之间双向通信的功能,简单列举了几个生成器的使用场景。

感谢您的拨冗阅读,希望对您有所帮助。

fa4d74689ed4eac2182c6bef8d04e5c2.jpeg


http://www.mrgr.cn/news/34072.html

相关文章:

  • 文科生学pytorch——一些概念的解释
  • layui upload.render 设置文件名
  • 基于Python+SQLServer实现(界面)书店销售管理管理子系统
  • 关于在vue2中给el-input框的placeholder加样式
  • CPLD 工程师面试题
  • AI美女占领小红书,卷翻真人女网红
  • HTML5简介的水果蔬菜在线商城网站源码系列模板3
  • Oracle数据库高级技术解析与实战案例
  • 【AIGC】ChatGPT提示词助力高效文献处理、公文撰写、会议纪要与视频总结
  • 详解运行时安全检测神器:Falco
  • [leetcode]70_单词搜索
  • 如何将py文件打包成exe文件?---pyinstaller使用方法
  • Java面试篇基础部分- 锁详解
  • 【C++掌中宝】玩转C++标准输入输出(简洁明了)
  • JVM面试问题集
  • 【aider】aider使用ollama本地模型
  • cmake--add_compile_options
  • MQ(消息队列)重启后消息是否会丢失
  • AI大模型优化指南:RAG、提示工程与微调的应用场景解析
  • vcpkg使用