迭代器与生成器

生成器(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
StopIteration异常:
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
yield : (返回并暂停)保持当前状态并中断,下次运行从这个状态开始
send(): 给yiield传值并调用  .__next__() 相当于 .send(None)
next:调用yield,唤醒它
 
做包子练习
 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
>>>

【你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。】

                                                  —https://www.cnblogs.com/alex3714/articles/5765046.html

Python—迭代器与生成器的更多相关文章

  1. Python 迭代器和生成器(转)

    Python 迭代器和生成器 在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的, ...

  2. 一文搞懂Python迭代器和生成器

    很多童鞋搞不懂python迭代器和生成器到底是什么?它们之间又有什么样的关系? 这篇文章就是要用最简单的方式让你理解Python迭代器和生成器! 1.迭代器和迭代过程 维基百科解释道: 在Python ...

  3. Python - 迭代器与生成器 - 第十三天

    Python 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问 ...

  4. 怎么理解Python迭代器与生成器?

    怎么理解Python迭代器与生成器?在Python中,使用for ... in ... 可以对list.tuple.set和dict数据类型进行迭代,可以把所有数据都过滤出来.如下:         ...

  5. Python迭代器,生成器--精华中的精华

    1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...

  6. python迭代器与生成器详解

    迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子. for 语句与可迭代对象(ite ...

  7. python -迭代器与生成器 以及 iterable(可迭代对象)、yield语句

    我刚开始学习编程没多久,对于很多知识还完全不知道,而有些知道的也是一知半解,我想把学习到的知识记录下来,一是弥补记忆力差的毛病,二也是为了待以后知识能进一步理解透彻时再回来做一个补充. 参考链接: 完 ...

  8. python迭代器,生成器

    1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...

  9. Python迭代器和生成器你学会了吗?

    在了解什么是迭代器和生成器之前,我们先来了解一下容器的概念.对于一切皆对象来说,容器就是对象的集合.例如列表.元祖.字典等等都是容器.对于容器,你可以很直观地想象成多个元素在一起的单元:而不同容器的区 ...

随机推荐

  1. android 前台服务不显示通知

    原因可以在哪里写了执行完成后就自动结束的吧 导致前台服务没有出现 如我 @Override public int onStartCommand(Intent intent, int flags, in ...

  2. 【Checkio Exercise】Robot Sort

    Robot Sort All of the refined ingots should be sorted by size in each lot while passing by on a conv ...

  3. Vue系列之 => 路由的嵌套

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  4. 使用fastdfs搭建文件服务器

    一:安装tracker 1. 拷贝安装目录下各个.gz文件到/usr/local/src下,解压各个install lib,例如tar zxvf xxx.tar.gz 2. 先安装libfastcom ...

  5. 如何将数据库中的数据导入到Solr中

    要使用solr实现网站中商品搜索,需要将mysql数据库中数据在solr中创建索引. 1.需要在solr的schema.xml文件定义要存储的商品Field. 商品表中的字段为: 配置内容是: < ...

  6. Shell if条件语句

    1.if条件语句:设定一个条件如果怎么,然后怎么样. (1)-gt大于.-lt小于.-ge大于等于.-le小于等于.-eq等于.-ne不等于. (2)[]内是包括变量时所使用的. (3)-f文件.-n ...

  7. Shell 脚本格式注意事项

    if 条件判断格式 if [ ! -f file.txt ];then cmd else cmd fi 注1:! 代表非.不存在文件就成功. 注2:再有参数 变量 需要 [] 阔起 1 运算书写写格式 ...

  8. 关于ashrpt中行源的CPU + Wait for CPU事件深入解读

    该等待事件并不包含在等待事件范围,而是出现在ash的具体行源中,如下: 标注语句的每次执行大约1小时,如下awr所示: 该sql语句的最后一层Insert如下: insert into ta_tf l ...

  9. 剑指offer(7)斐波那契数列

    题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项. n<=39 题目分析 我们都知道斐波那契可以用递归,但是递归重复计算的部分太多了(虽然可以通过),但是这 ...

  10. JS设计模式(12)装饰者模式

    什么是装饰者模式? 定义:动态地给一个对象添加一些额外的职责.就增加功能来说,装饰器模式相比生成子类更为灵活. 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且 ...