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

【python 生成器 面试必备】yield关键字,协程必知必会系列文章--自己控制程序调度,体验做上帝的感觉 1

python生成器系列文章目录

第一章 yield — Python (Part I)


文章目录

  • python生成器系列文章目录
  • 前言
  • 1. Generator Function 生成器函数
  • 2.并发和并行,抢占式和协作式
    • 2.Let’s implement Producer/Consumer pattern using subroutine:
  • 生成器的状态 generator’s states


前言

ref:https://medium.com/analytics-vidhya/yield-python-part-i-4dbfe914ad2d
这个老哥把yield讲清楚了,我来学习并且记录一下。


偶尔遇到Yield关键字时,它看起来相当神秘。这里,我们通过查看生成器如何使用yield获取值或将控制权返回给调用者来揭示yield所做的工作。我们也在看生成器generator的不同状态。让我们开始吧。

1. Generator Function 生成器函数

一个函数用了yield表达式后被称为生成器函数。

def happy_birthday_song(name='Eric'):yield "Happy Birthday to you"yield "Happy Birthday to you"yield f"Happy Birthday dear {name}"yield "Happy Birthday to you"
birthday_song_gen = happy_birthday_song() # generator creation
print(next(birthday_song_gen)) # prints first yield's value

birthday_song_gen 作为Generator被创建在第七行,相应的,生成器generator的执行通过调用next();
我们获得了yield的1个输出因为仅仅调用了一次next,接着generator是在suspend state(暂停/挂起状态),当另一个next()调用的时候,会激活执行并且返回第二个yield的值。像任何迭代器iterator一样,生成器将会exhausted 当stopIteration is encountered.

def happy_birthday_song(name='Eric'):yield "Happy Birthday to you"yield "Happy Birthday to you"yield f"Happy Birthday dear {name}"yield "Happy Birthday to you"birthday_song_gen = happy_birthday_song() # generator creation
print(next(birthday_song_gen)) # prints first yield's value# print rest of the yield's value
try:while True:print(next(birthday_song_gen))
except StopIteration:print('exhausted...')

2.并发和并行,抢占式和协作式

在这里插入图片描述
在这里插入图片描述
Cooperative multitasking is completely controlled by developer. Coroutine (Cooperative routine) is an example of cooperative multitasking.

Preemptive multitasking is not controlled by developer and have some sort of scheduler involved.

One of the ways to create coroutine in Python is generator.
在python中一种产生协程的做法是generator 生成器。

global 表示将变量声明为全局变量
nonlocal 表示将变量声明为外层变量(外层函数的局部变量,而且不能是全局变量)

def average():count = 0sum = 0def inner(value):nonlocal countnonlocal sumcount += 1sum += valuereturn sum/countreturn innerdef running_average(iterable):avg = average()for value in iterable:running_average = avg(value):print(running_average)
iterable = [1,2,3,4,5]
running_average(iterable)

输出:
在这里插入图片描述

The program control flow looks like this:
这个图要好好理解一下:
在这里插入图片描述

2.Let’s implement Producer/Consumer pattern using subroutine:

from collections import dequedef produce_element(dq, n):print('\nIn producer ...\n')for i in range(n):dq.appendleft(i)print(f'appended {i}')# if deque is full, return the control back to `coordinator`if len(dq) == dq.maxlen:yielddef consume_element(dq):print('\nIn consumer...\n')while True:while len(dq) > 0:item = dq.pop()print(f'popped {item}')# once deque is empty, return the control back to `coordinator`yielddef coordinator():dq = deque(maxlen=2)# instantiate producer and consumer generatorproducer = produce_element(dq, 5)consumer = consume_element(dq)while True:try:# producer fills dequeprint('next producer...')next(producer)except StopIteration:breakfinally:# consumer empties dequeprint('next consumer...')next(consumer)if __name__ == '__main__':coordinator() 

output looks like this:

C:\Users\HP\.conda\envs\torch1.8\python.exe "C:\Program Files\JetBrains\PyCharm 2021.1.3\plugins\python\helpers\pydev\pydevd.py" --multiproc --qt-support=auto --client 127.0.0.1 --port 59586 --file D:/code/python_project/01-coroutine-py-mooc/8/demo_ccc.py
Connected to pydev debugger (build 211.7628.24)
next producer...In producer..next consumer ...In consumer... popped 0
popped 1
next producer...
next consumer ...
popped 2
popped 3
next producer...
next consumer ...Process finished with exit code -1

过程解析:
生产2个,消费2个,再生产两个,再消费两个,再生产一个,触发StopIteration,再转向finall 消费1个 整个进程结束。
详细的看英语:
What’s happening? Well, the following thing is happening:

  1. create a limited size deque , here size of 2

  2. coordinator creates an instance of producer generator and also mentioning how many elements it want to generate

  3. coordinator creates an instance of consumer generator

  4. producer runs until deque is filled and yields control back to caller

  5. consumer runs until deque is empty and yields control back to caller

Steps 3 and 4 are repeated until all elements the producer wanted to produce is complete. This coordination of consumer and producer is possible due to we being able to control state of a control flow.

生成器的状态 generator’s states

    from inspect import getgeneratorstatedef gen(flowers):for flower in flowers:print(f'Inside loop:{getgeneratorstate(flower_gen)}')yield flowerflower_gen = gen(['azalea', 'Forsythia', 'violas'])print(f"After generator creation:{getgeneratorstate(flower_gen)}\n")print('getting 1st flower')print("--==", next(flower_gen))print(f'After getting first flower: {getgeneratorstate(flower_gen)}\n')print(f'Get all flowers: {list(flower_gen)}\n')print(f'After getting all flowers: {getgeneratorstate(flower_gen)}')

输出:

C:\Users\HP\.conda\envs\torch1.8\python.exe D:/code/python_project/01-coroutine-py-mooc/8/demo_ccc.py
After generator creation:GEN_CREATEDgetting 1st flower
Inside loop:GEN_RUNNING
--== azalea
After getting first flower: GEN_SUSPENDEDInside loop:GEN_RUNNING
Inside loop:GEN_RUNNING
Get all flowers: ['Forsythia', 'violas']After getting all flowers: GEN_CLOSEDProcess finished with exit code 0

We have a handy getgeneratorstate method from inspect module that gives state of a generator. From the output, we see there are four different states:

  1. GEN_CREATED
  2. GEN_RUNNING
  3. GEN_SUSPENDED
  4. GEN_CLOSED
    GEN_CREATED is a state when we instantiate a generator. GEN_RUNNING is a state when a generator is yielding value. GEN_SUSPENDED is a state when a generator has yielded value. GEN_CLOSED is a state when a generator is exhausted.

In summary, yield is used by generators to produce value or give control back to caller and generator has 4 states.

My next article will be sending values to generators!
下一篇文章介绍如何传值到生成器

http://www.lryc.cn/news/230379.html

相关文章:

  • 头哥实践平台之MapReduce基础实战
  • Linux基础知识——tmux和vim
  • Java Web——TomcatWeb服务器
  • Zookeeper 命令使用和数据说明
  • 索尼RSV文件怎么恢复为MP4视频
  • pytorch-gpu(Anaconda3+cuda+cudnn)
  • 解析数据洁净之道:BI中数据清理对见解的深远影响
  • efcore反向共工程,单元测试
  • 利用IP风险画像强化金融行业网络安全防御
  • 1334. 阈值距离内邻居最少的城市
  • Live800:客服行业的发展历程及未来前景
  • exsi的安装和配置
  • 基于springboot实现校园医疗保险管理系统【项目源码】
  • Python 如何实现组合(Composite)设计模式?什么是组合设计模式?
  • 编辑器vim和编译器gcc/g++
  • linux 系统下文本编辑常用的命令
  • 3D Gaussian Splatting文件的压缩【3D高斯泼溅】
  • Spring Boot 整合xxl-job实现分布式定时任务
  • 16.最接近的三数之和
  • php 插入排序算法实现
  • import gradio时出现SyntaxError: future feature annotations is not defined解决方案
  • 视频封装格式
  • vue+iView实现下载zip文件导出多个excel表格
  • Rust编程中的共享状态并发执行
  • python语法之数据类型
  • Skybox天空盒子的更换教程_unity基础开发教程
  • Android模拟器的linux内核源码的下载
  • Vue中methods实现原理
  • 维基百科是非营利性机构 词条内容具有中立性、准确性、可靠性
  • C/C++轻量级并发TCP服务器框架Zinx-框架开发002: 定义通道抽象类