博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
迭代器和生成器
阅读量:5255 次
发布时间:2019-06-14

本文共 5193 字,大约阅读时间需要 17 分钟。

迭代器

可以把迭代器比喻成一个容器,可以从这个容器中一个接一个的把值取出来,取值的过程就是可迭代的过程

  可迭代协议:含有__iter__方法

  迭代器协议:含有__iter__方法 且 __next__方法

  查看方法:print(l1.__dir__)

可迭代对象: 含有__iter__方法 

迭代器: 含有__iter__方法和__next__方法 迭代器.__next__ 调用迭代器

(迭代器 是 可迭代对象 的 子集)

第一种判断方法:

  判断是不是可迭代:print('__iter__' in dir(对象)) 对象可以是字符串、列表、字典、等等

  判断是不是迭代器:print('__next__' in dir(对象)) 

第二种判断方法:

from collections import Iterablefrom collections import Iteratorprint(isinstance(对象,Iterable))   # 判断是不是可迭代的print(isinstance(对象,Iterator))   # 判断是不是迭代器

例如:

li = []a = li.__iter__()from collections import Iteratorfrom collections import Iterableprint(isinstance([1,2],Iterable))       #从功能上判断    而type()是类型  是就是  不是就不是print(isinstance([1,2],Iterator))print(isinstance(a,Iterator))# True# False# True

迭代器的特点:

  从前往后依次去取值,不可逆,不可重复
  惰性运算
  节省内存

取值超出范围,会抛出一个异常:

li = [1,2,3,4,5]li_iter = li.__iter__()print(li_iter.__next__())print(li_iter.__next__())print(li_iter.__next__())print(li_iter.__next__())print(li_iter.__next__())print(li_iter.__next__())#Traceback (most recent call last):#  File "D:/Demo/test2.py", line 26, in 
# print(li_iter.__next__())#StopIteration 超出5次 报错 StopIteration

while 模拟 for

li = [1,2,3,4,5]li_iter = li.__iter__()while True:    try:        print(li_iter.__next__())    except StopIteration:          #StopIteration  报出异常        break

python3内置迭代器:

    内置迭代器:range() file(文件for循环读) enumerate()

生成器

生成器的本质: 就是 迭代器 内含__next__()方法,

一个函数里面如果有yield,那么这个函数就是生成器函数

def ge_iter():              #ge_iter()  就是生成器函数           生成器函数  里面有    yield关键字    print('aa')    yield 11        # 见到yield 取一次值,且记住这个位置,下次直接从这里开始    print('bb')    yield 15    yield 1    yield 2g = ge_iter()         # ge_iter()是生成器               生成器就是迭代器,能用__next__方法取值print(g.__next__())# aa# 11

while取值:

def ge_iter():    print('aa')    yield 11    print('bb')    yield 15    yield 1    yield 2g = ge_iter()           调用ge_iter()不会立即执行,而是返回一个生成器while True:    try:        print(g.__next__())    except StopIteration:        break

for循环取值:

def ge_iter():    for i in range(10):        yield "我是第{}名".format(i)g = ge_iter()print(g.__next__())print(g.__next__())for i in range(3):                # for循环取一段值    print(g.__next__())      # 会接着上次保存的位置,接着取值# 我是第0名# 我是第1名# 我是第2名# 我是第3名# 我是第4名

生成器惰性特点:

def fuc1(n,i):    return n + idef duoxing():    for i in range(4):        yield ig = duoxing()for n in [1,10]:    g = (fuc1(n,i) for i in g)    关键点:因为生成器不取值(不打印),就永远不去运算,不运算,但for不停,                                            所以最后 g = (fuc1(n,i) for i in (fuc1(n,i) for i in duoxing()))   print(list(g))                      直接把 n = 10 带入计算# [20, 21, 22, 23]

生成器取值,取了就没了:

def fuc1(n,i):    return n + idef duoxing():    for i in range(4):        yield ig = duoxing()for n in [1,10]:    g = (fuc1(n,i) for i in g)                                                   print(list(g))                          第一次取值了,g生成器就没了            不管循环多少次,只有第一次有值,取空了,后面都是空列表#[1, 2, 3, 4]#[]

==

一个生成器如下:

def cloth():    for i in range(100):        yield ‘衣服%’%ig = cloth()

取值:

for i in g:     print(i)#等价于 for i in range(100):    print(g.__next__())  #循环触发打印100次

for 自动触发可迭代g内部next方法 想当于第二个手动触发

为什么用for 是因为 next() 和send()有可能遇到取完再取的报错

而for循环取完就停止了

示例:文件的监视,监听文件的变化

def tail():    f = open('文件','r',encoding='utf-8')    f.seek(0,2)      #把光标定位到文件末尾    while True:        line = f.readline()  #从光标的位置读        if line:         #line如果有内容  True            yield line        import time        time.sleep(0.1)g = tail()for i in g:    print(i.strip())##注意 文件输入一定要保存 要不然显示不出来

send()方法

__send__() 可以写成send()

__next__() 可以写成next()

def f1():    a = 1    b = yield a   #执行到yield a 停止  返回a = 1    ***    send传值,想当于把yield a 替换 , 变成b = 5 ,继续往下走    yield b   #定位到yield b   又停止,返回 b = 5g = f1()print(next(g))print(g.send(5))#1#5

send 想当于next的同时传参( send(None) == next() ) 把生成器里面yield及后面的值整体替换成传入的参数

send不能 用在第一个触发生成器

next + send 数量和 = yield 数量

预激活装饰器

正常情况,需要用next()方法取值一次,才能用send()方法

#每传一个数,求每次传入后的平均值def average():    sum = 0    count = 0    aver_age = None    while True:        count += 1        a = yield aver_age        sum += a        aver_age = sum/countg_aver = average()print(g_aver.__next__())print(g_aver.send(10))print(g_aver.send(20))print(g_aver.send(30))#10#15#20

可以利用装饰器,把第一个next()方法放到装饰器里面

def init(func):    def inner(*args,**kwargs):        g = func(*args,**kwargs)        next(g)        return g         #这个地方一定要返回一个生成器    return inner@initdef average():    sum = 0    count = 0    aver_age = None    while True:        count += 1        a = yield aver_age       #yield后面放什么都行,这个主要是只要一个yield,来返回aver_age 的值        sum += a        aver_age = sum/countg_aver = average()       #得到生成器,并赋值给g_aver,这一步不能省略,如果写成print(average.send(10)),想当于每次都重新调用average函数# print(g_aver.__next__())   #这一步放到装饰器函数里面,预激活print(g_aver.send(10))print(g_aver.send(20))print(g_aver.send(30))

yield from   

代替for 循环

for i in a:

  yield i

for i in a:    yield i# 等价于yield from a

示例:

a = ‘abcd’  依次拿到‘a','b','c','d'def func():    a = 'abcd'    for i in a:    #这        yield i     #两句g = func()print(list(g))# ['a', 'b', 'c', 'd']------def func():    a = 'abcd'    yield from a   #这一句g = func()print(list(g))# ['a', 'b', 'c', 'd']

 

转载于:https://www.cnblogs.com/jin-yuana/p/10024929.html

你可能感兴趣的文章
PHP截取中英文混合字符
查看>>
【洛谷P1816 忠诚】线段树
查看>>
电子眼抓拍大解密
查看>>
poj 1331 Multiply
查看>>
tomcat7的数据库连接池tomcatjdbc的25个优势
查看>>
Html 小插件5 百度搜索代码2
查看>>
P1107 最大整数
查看>>
多进程与多线程的区别
查看>>
Ubuntu(虚拟机)下安装Qt5.5.1
查看>>
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
查看>>
java 常用命令
查看>>
CodeForces Round #545 Div.2
查看>>
卷积中的参数
查看>>
51nod1076 (边双连通)
查看>>
Item 9: Avoid Conversion Operators in Your APIs(Effective C#)
查看>>
深入浅出JavaScript(2)—ECMAScript
查看>>
STEP2——《数据分析:企业的贤内助》重点摘要笔记(六)——数据描述
查看>>
ViewPager的onPageChangeListener里面的一些方法参数:
查看>>
Jenkins关闭、重启,Jenkins服务的启动、停止方法。
查看>>
CF E2 - Array and Segments (Hard version) (线段树)
查看>>