知识点:从迭代器一直撸到yield from
最近在跟一个系列,
难度和篇幅比较合适我这样的懒人。
敲下代码,作下注释,看看输出,就蛮好。
https://www.cnblogs.com/wongbingming/p/9095243.html
import collections from collections.abc import Iterable, Iterator, Generator from inspect import getgeneratorstate """ 借助collections.abc这个模块, 使用isinstance()来类别一个对象是否是可迭代的(Iterable), 是否是迭代器(Iterator), 是否是生成器(Generator)。 """ astr = "XiaoMing" print("String: {}".format(astr)) print(isinstance(astr, Iterable)) print(isinstance(astr, Iterator)) print(isinstance(astr, Generator)) # String: XiaoMing # True # False # False """ 从结果来看,这些可迭代对象都不是迭代器,也不是生成器。 它们有一个共同点,就是它们都可以使用for来循环。 """ alist = [21, 45, 65, 78] print("List: {}".format(alist)) print(isinstance(alist, Iterable)) print(isinstance(alist, Iterator)) print(isinstance(alist, Generator)) # List: [21, 45, 65, 78] # True # False # False adict = {'name': "xiaoming", 'age': 18} print("Dict: {}".format(adict)) print(isinstance(adict, Iterable)) print(isinstance(adict, Iterator)) print(isinstance(adict, Generator)) # Dict: {'name': 'xiaoming', 'age': 18} # True # False # False """ 可迭代对象,是其内部实现了,__iter__ 这个魔术方法。 可以通过,dir()方法来查看是否有__iter__来判断一个变量是否是可迭代的。 """ adeque = collections.deque('abcdefg') print("deque: {}".format(adeque)) print(isinstance(adeque, Iterable)) print(isinstance(adeque, Iterator)) print(isinstance(adeque, Generator)) # deque: deque(['a', 'b', 'c', 'd', 'e', 'f', 'g']) # True # False # False """ 对比可迭代对象,迭代器其实就只是多了一个函数而已。 就是__next__(),我们可以不再使用for循环来间断获取元素值。 而可以直接使用next()方法来实现。 可以通过,dir()方法来查看是否有__next__来判断一个变量是否是迭代器的 """ aIterator = iter(astr) print("aIterator: {}".format(aIterator)) print(isinstance(aIterator, Iterable)) print(isinstance(aIterator, Iterator)) print(isinstance(aIterator, Generator)) # aIterator: <str_iterator object at 0x00000000023F5358> # True # True # False """ 而生成器,则是在迭代器的基础上(可以用for循环,可以使用next()),再实现了yield。 yield 是什么东西呢,它相当于我们函数里的return。 在每次next(),或者for遍历的时候, 都会yield这里将新的值返回回去,并在这里阻塞,等待下一次的调用。 正是由于这个机制,才使用生成器在Python编程中大放异彩。 实现节省内存,实现异步编程。 可迭代对象和迭代器,是将所有的值都生成存放在内存中, 而生成器则是需要元素才临时生成,节省时间,节省空间。 """ aGenerator = (x*x for x in range(10)) print("aGenerator: {}".format(aGenerator)) print(isinstance(aGenerator, Iterable)) print(isinstance(aGenerator, Iterator)) print(isinstance(aGenerator, Generator)) # aGenerator: <generator object <genexpr> at 0x0000000002727FC0> # True # True # True """ 由于生成器并不是一次生成所有元素,而是一次一次的执行返回, 那么如何刺激生成器执行(或者说激活)呢? 激活主要有两个方法 使用next() 使用generator.send(None) 通过交替执行,说明这两种方法是等价的。 """ gen = aGenerator print(gen.send(None)) print(next(gen)) print(gen.send(None)) print(next(gen)) print(gen.send(None)) print(next(gen)) # # # # # """ 生成器在其生命周期中,会有如下四个状态 GEN_CREATED # 等待开始执行 GEN_RUNNING # 解释器正在执行(只有在多线程应用中才能看到这个状态) GEN_SUSPENDED # 在yield表达式处暂停 GEN_CLOSED # 执行结束 在生成器工作过程中, 若生成器不满足生成元素的条件, 就会/应该 抛出异常(StopIteration)。 我们在自己定义一个生成器的时候, 我们也应该在不满足生成元素条件的时候,抛出异常。 """ def mygen(n): now = 0 while now < n: yield now now += 1 # 抛出异常 raise StopIteration gen2 = mygen(2) print(getgeneratorstate(gen2)) print(next(gen2)) print(getgeneratorstate(gen2)) print(next(gen2)) gen2.close() print(getgeneratorstate(gen2)) # GEN_CREATED # # GEN_SUSPENDED # # GEN_CLOSED """ 协程和线程,有相似点,多个协程之间和线程一样,只会交叉串行执行; 也有不同点,线程之间要频繁进行切换,加锁,解锁, 从复杂度和效率来看,和协程相比,这确是一个痛点。 协程通过使用 yield 暂停生成器, 可以将程序的执行流程交给其他的子程序, 从而实现不同子程序的之间的交替执行。 """ def jumping_range(N): index = 0 while index < N: # yield index 是将index return给外部调用程序。 # jump = yield 可以接收外部程序通过send()发送的信息,并赋值给jump jump = yield index if jump is None: jump = 1 index += jump # 抛出异常 raise StopIteration itr = jumping_range(5) print(next(itr)) print(itr.send(2)) print(itr.send(-1)) print(itr.send(None)) print(next(itr)) print(itr.send(-2)) print(next(itr)) # # # # # # """ yield from后面加上可迭代对象, 他可以把可迭代对象里的每个元素一个一个的yield出来, 对比yield来说代码更加简洁,结构更加清晰。 """ def gen3(*args, **kwargs): for item in args: yield from item new_list = gen3(astr, alist, adict, aGenerator) print(list(new_list)) # ['X', 'i', 'a', 'o', 'M', 'i', 'n', 'g', 21, 45, 65, 78, 'name', 'age', 36, 49, 64, 81] # 子生成器 def average_gen(): total = 0 count = 0 average = 0 while True: # 子生成器yield的值,直接返回给调用方。 new_num = yield average if new_num is None: break count += 1 total += new_num average = total/count # 每一次return,都意味着当前协程结束。 return total, count, average # 委托生成器 # 作用是:在调用方与子生成器之间建立一个双向通道。 def proxy_gen(): while True: # 只有子生成器要结束(return)了, # yield from左边的变量才会被赋值,后面的代码才会执行。 total, count, average = yield from average_gen() print("计算完毕!!\n总共传入 {} 个数值, 总和:{},平均数:{}" .format(count, total, average)) # 调用方 def main_gen(): calc_average = proxy_gen() next(calc_average) # 调用方可以通过send()直接发送消息给子生成器 print(calc_average.send(10)) print(calc_average.send(20)) print(calc_average.send(30)) calc_average.send(None) # 结束协程 # 如果此处再调用calc_average.send(10),由于上一协程已经结束,将重开一协程 main_gen() # 10.0 # 15.0 # 20.0 # 计算完毕!! # 总共传入 3 个数值, 总和:60,平均数:20.0
知识点:从迭代器一直撸到yield from的更多相关文章
- 【Python】迭代器、生成器、yield单线程异步并发实现详解
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
- Python:容器、迭代对象、迭代器、生成器及yield关键字
在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list, ...
- python迭代器与生成器及yield
一.迭代器(itertor) 1.可迭代: 在Python中如果一个对象有__iter__()方法或__getitem__()方法,则称这个对象是可迭代的(iterable). 其中__iter__( ...
- python迭代器、生成器、yield理解
简介 yield关键字是python的一种高阶用法,使用yield的函数会返回一个生成器对象,生成器又是一个迭代器,与迭代器相类似的则是可迭代对象,下面首先介绍一下迭代器吧. 迭代器 在python中 ...
- Python知识点进阶——迭代器
可迭代对象 可迭代对象可以简单的理解为用for循环遍历的,如list.tuple.dict.set.str 判断一个对象是否是迭代器: 可以将数据类型 和 是否为可迭代对象 比较来判断是否是可以迭代 ...
- python迭代器、生成器、yield和xrange
https://blog.csdn.net/u010138758/article/details/56291013
- yield 关键字和迭代器
一般使用方法 yield 关键字向编译器指示它所在的方法是迭代器块 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返回值,例如,在 forea ...
- 初次使用C#中的yield
这几天在Python程序员的微信订阅号中总是见到yield的关键字,才想起来在C#中也是有yield,但是只是知道有,从来没有了解过他的用法,今天有时间就来看看是怎么使用的.刚开始肯定就是搜索一下用法 ...
- Python迭代器,生成器--精华中的精华
1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...
随机推荐
- CentOS6.x下源码安装MySQL5.5
1. 更新yum源:http://www.cnblogs.com/vurtne-lu/p/7405931.html 2. 卸载原有的mysql数据库 [root@zabbix ~]# yum -y r ...
- bzoj千题计划307:bzoj5248: [2018多省省队联测]一双木棋
https://www.lydsy.com/JudgeOnline/problem.php?id=5248 先手希望先手得分减后手得分最大,后手希望先手得分减后手得分最小 棋盘的局面一定是阶梯状,且从 ...
- EventKey为last_trade_no的subscribe关注事件
如果用户曾经在该公众号有支付行为,关注的时候EventKey中将包含上次交易订单号,如 last_trade_no_4002752001201704258347703919 <xml> & ...
- C# 反编译项目修复
1.反编译测试程序 1>.将测试程序添加到.NET Reflector 2>.选中测试程序后右键选择导出 2.反编译项目修复 1>.问题一 问题现象: base.AutoScaleM ...
- 使用css将图像居中
默认情况下,图像属于内联元素.这意味着它们与周围的文本一起流动.为使图像居中,我们应该将其转换成块级元素,通过将display属性的值设置为block就可以完成转换. <html> < ...
- JavaScript练习 - 正反选练习
正反选练习 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- android的五个进程优先级,内存不足时被清理的顺序
Android操作系统尝试尽可能长时间的保持应用的进程,但当可用内存很低时最终要移走一部分进程.怎样确定那些程序可以运行,那些要被销毁,Android让每一个进程在一个重要级的基础上运行,重要级低的进 ...
- curl命令下载jdk
第一步:找到下载地址 第二步:下载
- python实战===教你用微信每天给女朋友说晚安
但凡一件事,稍微有些重复.我就考虑怎么样用程序来实现它. 这里给各位程序员朋友分享如何每天给朋友定时微信发送”晚安“,故事,新闻,等等··· ···最好运行在服务器上,这样后台挂起来更方便. 准备: ...
- VS "以下文件中的行尾不一致,要将行尾标准化吗?"
原文地址:http://www.cnblogs.com/yymn/p/6852857.html 这是由Windows和Unix不同的标准引起的...即“回车”和“换行”的问题... “回车”和“换行” ...