Python—迭代器与生成器
迭代器与生成器
生成器(generator)
先来了解一下列表生成器:
list = [i*2 for i in range(10)]
print(list)
>>>>
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
gen1 = (i*2 for i in range(10))
print(gen1)
>>>>>
<generator object <genexpr> at 0x0000022419B21AF0> #列表生成器打印出来只是一个内存地址
要注意的是:
1.打印生成器,只是打印其内存地址,生成器只有在调用的时候,才会产生元素,只能一个个取值
2.生成器不能像列表一样访问某个元素,或者切片。只能通过for循环打印出来,或者通过 【__next__()】,括号里不能给参数 2.7里 是 next()
3.生成器只有一个 __next__() 方法,生成器只会记住当前的取值,可以用next方法调用下一个,但是不能往前,内置函数 next也可以调用,for循环也可以调用,还可以数据类型强制转换: list(generator)
>在一次运行过程中,生成器遍历取值完就没有值了。 迭代器也是遍历完就没有值了,同样也会有 StopIteration Error
>生成器是一类特殊的迭代器。在函数中用 yield
#for循环调用生成器,,yield不能和return共用,且要写在函数内部
>>> def generator():
print(1)
yield 33333 #可以把yield看成return一个值,但是不结束函数,只是暂时中断
print(2)
yield 44444 >>> g = generator() #此时g就是一个生成器,generator就是iterator,所以可以用for循环
>>> for i in g:
print(i)
---->
1
33333
2
44444
>>>
用函数生成生成器,以斐波那契数列进行举例(yield不能和return共用,且要写在函数内部)
def fibo(max):
n,a,b = 0,0,1
while n<max:
#print(b)
yield b #生成器的创建 yield:(返回后暂停)保持当前状态并中断函数,下次运行时,从这里往后运行,因为保存了当前状态
a,b = b,a+b #相当于 t =(b,a+b) a = t[0] b = [t1]
n +=1
return 'done' f = fibo(10)
print(f.__next__())
print(f.__next__())
print('----做点别的事情----') #生成器可以调用一下,然后停下来做别的事,其他函数会一口气打印出所有结果
print(f.__next__())
print(f.__next__())
print('----开始for循环----') #__next__方法只记录当前位置
for i in f:
print(i) >>>>>#结果如下所示
1
1
----做点别的事情----
2
3
----开始for循环----
5
8
13
21
34
55
def fibo(max):
n,a,b = 0,0,1
while n<max:
#print(b)
yield b
a,b = b,a+b #相当于 t =(b,a+b) a = t[0] b = [t1]
n +=1
return '----done----' f = fibo(3) #只运行3次斐波那契数列
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__()) #此时调用了4次next方法 ,此时会报 StopIteration错误 >>>>>>
Traceback (most recent call last):
1
File "C:/Users/15302/PycharmProjects/GKXXX/day3/斐波那契数列.py", line 20, in <module>
1
print(f.__next__())
2
StopIteration: ----done---- #这个done是函数返回值
可以用【try—except】来抓住异常(for循环用的就是这种机制)
def fibo(max):
‘--snip--’ f = fibo(5)
while True: #用 try—except 来抓住异常
try:
x = next(f)
print('斐波那契数列:',x) #打印每次运行generator的值
except StopIteration as e: #抓住StopIteration异常
print('Generator return value:',e.value) #输出返回值
break >>>>>
斐波那契数列: 1
斐波那契数列: 1
斐波那契数列: 2
斐波那契数列: 3
斐波那契数列: 5
Generator return value: ----done----
关于yield(yield类似return,如果不打印是不显示yield的值的,只会执行程序)
def gen():
print('start')
m = yield 2 # 可以看作yield返回值为2,send(3)把3传递给m,并调用,m变成3了,同下
print(m)
n = yield 3
print(n) try:
g = gen() #此时不运行gen()函数,若print(g) 会打印该生成器的内存地址
g.send(None) # 相当于 g.__next__() 此处若 print(g.send(None)) 则先执行 打印start,然后执行 打印 yiled的返回值 2,然后函数暂停
g.send(3333) #此处若 print(g.send(3333)) 首先函数继续往下走,先把send里的3333赋值给m,然后打印m,接下来执行 yield 3的返回值,打印3
g.send(6666)
except StopIteration as e:
print(e.value) >>>>
start
3333
6666
None
import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) # c = consumer('gkx') #此时不运行程序,即当函数中有yield时候,一定要用 __next__,send()方法调用才会运行,这句话相当于把函数变成生成器而已
# c.__next__() #第一次运行到 yield,然后保存当前状态,停止
# b1 = 'jiucai'
# c.send(b1)
#c.__next__() #运行yield往后的语句,即第二句 print处
def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i) producer("gkx")
迭代器
1.凡是可作用于for循环的对象都是Iterable类型; 可迭代协议— 只要含有 __iter__方法的都是可迭代的
1 >>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance((),Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance(‘abc’,Iterable)
True
>>> isinstance((x for x in range(10)),Iterable)
True
>>> isinstance(100,Iterable)
False 15 #list,set,dict,str,generatior都是可迭代的,数字不可迭代 print('__iter__' in dir([])) >>>>>简单粗暴的判断方法
2.凡是可作用于next()函数的对象都是Iterator(迭代器)类型,它们表示一个惰性计算的序列;(生成器一定是迭代器,迭代器不一定是生成器)
迭代器协议:含有 __next__ 和 __iter__方法的,就是迭代器
1 >>> from collections import Iterator
>>> isinstance((x for x in range(10)),Iterator)
True
>>> isinstance([],Iterator)
False
>>> isinstance({},Iterator)
False
>>> isinstance('abc',Iterator)
False
>>> 12 #在dict,set,list,str,generator中,只有generator才是迭代器
3.集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
from collections import Iterator
1 >>> isinstance(iter([]),Iterator)
True
>>> isinstance(iter({}),Iterator)
True
>>> a = ['1','2']
>>> iter(a)
<list_iterator object at 0x00000262D6E85F60>
>>> iter(a).__next__() #把列表a转换为迭代器,可以使用__next__()函数
'1'
>>>
我们在文件操作中,用 for line in f: 其中 文件句柄 f 就是迭代器
for循环等价于:
>>> it = iter(range(10))
>>> while True:
try:
x = next(it)
print(x)
except StopIteration:
break 0
1
2
3
4
5
6
7
8
9
>>>
【你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。】
—https://www.cnblogs.com/alex3714/articles/5765046.html
Python—迭代器与生成器的更多相关文章
- Python 迭代器和生成器(转)
Python 迭代器和生成器 在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的, ...
- 一文搞懂Python迭代器和生成器
很多童鞋搞不懂python迭代器和生成器到底是什么?它们之间又有什么样的关系? 这篇文章就是要用最简单的方式让你理解Python迭代器和生成器! 1.迭代器和迭代过程 维基百科解释道: 在Python ...
- Python - 迭代器与生成器 - 第十三天
Python 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问 ...
- 怎么理解Python迭代器与生成器?
怎么理解Python迭代器与生成器?在Python中,使用for ... in ... 可以对list.tuple.set和dict数据类型进行迭代,可以把所有数据都过滤出来.如下: ...
- Python迭代器,生成器--精华中的精华
1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...
- python迭代器与生成器详解
迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子. for 语句与可迭代对象(ite ...
- python -迭代器与生成器 以及 iterable(可迭代对象)、yield语句
我刚开始学习编程没多久,对于很多知识还完全不知道,而有些知道的也是一知半解,我想把学习到的知识记录下来,一是弥补记忆力差的毛病,二也是为了待以后知识能进一步理解透彻时再回来做一个补充. 参考链接: 完 ...
- python迭代器,生成器
1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...
- Python迭代器和生成器你学会了吗?
在了解什么是迭代器和生成器之前,我们先来了解一下容器的概念.对于一切皆对象来说,容器就是对象的集合.例如列表.元祖.字典等等都是容器.对于容器,你可以很直观地想象成多个元素在一起的单元:而不同容器的区 ...
随机推荐
- 两个有序数组的上中位数和第K小数问题
哈,再介绍个操蛋的问题.当然,网上有很多解答,但是能让你完全看懂的不多,即便它的结果是正确的,可是解释上也是有问题的. 所以,为了以示正听,我也做了分析和demo,只要你愿意学习,你就一定能学会,并且 ...
- js高级---本地对象、内置对象、宿主对象
名词参考: 原生对象:也叫内部对象.本地对象.native object 内置对象:Build-in object 宿主对象:host object ECMA-262 定义: 原生对象:独立于宿主环境 ...
- 第五篇——Struts2的默认Action
默认Action 1.当访问action不存在时,可以通过制定默认action的方式避免出现错误代码页面: 2.使用default-action-ref 指定默认 action. 项目实例 1.项目结 ...
- java-面向对象的多态性摘要
多态的作用就是用来将接口和实现分离开,改善代码组织结构,增强代码可读性,便于代码的维护. 在java中,讨论多态就是讨论方法调用的绑定,绑定就是将一个方法调用同一个方法主体联系起来.在java中通常叫 ...
- LATCH_VARIANT = Magna compile
after: LATCH_VARIANT = Magna in m_project_cfg.mak of PG_.. 1. first error: SED tmp__.dep/bin/sh: / ...
- Java正则表达式草稿程序*2
1.成绩统计. 输入文件input.txt: 张三 语文12 数学31 英语11 李四 语文22 数学22 英语22 王五 语文33 数学33 英语33 期待输出output.txt: 张三 语文12 ...
- springboot shiro和freemarker集成之权限控制完全参考手册(跳过认证,登录由三方验证,全网首发)
本文主要考虑单点登录场景,登录由其他系统负责,业务子系统只使用shiro进行菜单和功能权限校验,登录信息通过token从redis取得,这样登录验证和授权就相互解耦了. 用户.角色.权限进行集中式管理 ...
- 复旦大学2016--2017学年第二学期(16级)高等代数II期末考试第六大题解答
六.(本题10分) 设 $A$ 为 $n$ 阶半正定实对称阵, $S$ 为 $n$ 阶实反对称阵, 满足 $AS+SA=0$. 证明: $|A+S|>0$ 的充要条件是 $r(A)+r(S)= ...
- 《温故而知新》JAVA基础四
类的封装 定义:将类的一些信息隐藏起来,不允许外部的程序直接的访问,而是通过该类提供的一些方法来获取 好处:只能通过特定的法方法访问数据,保护了数据, 实现封装的步骤: 修改属性的可见性:(一般类属性 ...
- antd Select进阶功能 动态更新、函数防抖
一.动态更新Options Antd Select自带的搜索功能很多时候需要结合后端的接口,输入一个关键字的时候会自动更新选择器的选项. 下面列一些注意点 基础实现 选择器选项必须和每次更新的数据挂钩 ...