迭代器和生成器

python学习初期,学习到for循环可以循环取出目标中的值,再对逐一取到的值进行后续操作,虽然知其用法,但是不知其原理

随着学习的深入,会接触到一个新‘术语’,迭代

迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值

所谓迭代(个人解读):一篮子鸡蛋里有一个鹅蛋,鹅蛋在篮子里的任意一个地方,规定一次只能拿一颗蛋,直到拿到鹅蛋为止,迭代的目标就是要拿到鹅蛋,迭代就是拿蛋的过程,每一次拿蛋的动作都是一次迭代,而每次拿到的蛋都独一无二、拿一个少一个

可迭代对象:在容器(你可以理解为篮子)里,可逐一取出

那就引申出一个问题,在python中如何判断目标是否是可迭代对象呢?方法如下:

from collections import iterable
print(isinstance('aaa',iterable))

就是这样了,判断给出的答案只有两个,非True即False,我英语不好,所以不要问为什么,记着就行了T-T

iterable  可迭代的

instance  情况  isinstance  判断目标是否是某已知数据类型

 

说完什么是迭代,和判断是否是可迭代对象的方法以后,终于可以开始说正主了orz...

 

一、迭代器(iterator)

如果一定要把迭代归类成一种计算或取值方法,那么常规选择都是便利的for循环

但是如果一定要指定一个特定的功能定式出来,那么就记住

如果某数据类型点儿出来的功能里,有‘__iter__’,那么此数据类型可迭代

迭代器,就是具体实施,实现一次一次迭代的工具~~so~~简单粗暴

li = [1,2,3]
li.__iter__()    
#就这样,莫名其妙的,变成了迭代器,what?...so...我也不晓得为什么,可能就像藏族选活佛一样吧,找几个有灵性的小孩备选,选中的那个,经过授权,就成为了活佛...
#那么可迭代对象只要穿上了‘双下iter’的衣服,就摇身一变,功能升级,变成了迭代器...

本质:目前就我所知,迭代器存在的目的是,因为本身是惰性运算,所以可以更好的节省内存,但功能和for没啥区别,还比for麻烦

迭代器的功能有二:‘__iter__’和‘__next__’,所以这也可以用于判断是否是迭代器,就看有没有这俩功能

迭代器有两种:

1,天生的,如:文件句柄

2,后天的,可迭代对象.__iter__()

 

二、生成器

生成器就是我们自己写出来的迭代器...(所以弄出来这么多拗口的概念是不是精神分裂,让我回想起了大学时让人恨的牙痒痒的那些人名,高斯、拉格朗日...)

生成器有两种:

1,生成器函数(顾名思义,写在函数里的,有迭代器功能的)

需要注意的:yield是标志,有它才是生成器(写两个以上yield就可以写成生成器,如果只有一个yield,麻烦还是不要脱裤子放屁了...)

yield的两项功能:⑴当return用,可以返回值⑵有个记账儿的小本儿,运行到哪下次继续

注意:生成器是个好人,内容只取一次,按顺序不回头,取完所有或人为写代码停止才停(简直任劳任怨,还不翻小肠)

示例:

1.
def generator_func():
    print(123)
    yield 'aaa'
    print(456)
    yield 'bbb'

2.
def get_clothing():
    for cloth in range(1,20000):
        yield '第%s件衣服'%cloth
for i in range(50):
    print(get_clothing())    #稀里哗啦打印出50件~~~
for i in get_clothing():
    print(i)
    if i == '第100件衣服':
        break                #打印到100件的时候,人为叫停~~~

监视文件示例(广大女性的福音,是否可以发展成小程序,后台监控男朋友老公的聊天记录...):

import time        #调用时间
def tail(filename):
    f = open(filename,encoding='utf-8')    #读文件
    f.seek(0,2)    #光标找到文件末端
    while True:    #循环监视~~
        line = f.readline()    #一行一行的读取文件内容
        if not line:    #如果没啥内容
            time.sleep(0.1)    #0.1秒运行一次监视~~
            continue    #没啥内容就算了
        yield line    #返回文件新写入的内容
tail_g = tail('demo')    #调用函数生成器,传入要监视的文件
for line in tail_g:    
    print(line,end='')    #好了,你想看的,都在这儿了...满意了么...

 2.生成器表达式(内含列表推导式)

在此之前,需要说一下什么是列表推导式,以往我们在列表里取值,或想要对列表里的每一项进行一些操作的时候,都使用for循环

li = [1,2,3,4]
for i in li:
    print(i)

#那么是时候使用这种更言简意赅的表达方法了——列表推导式

写成:
print([i for i in li])

注意:列表推导式需要放在列表中,尽量使用此写法简化代码,增强代码的可读性,切忌秀操作...

为什么要先插播列表推导式呢?

因为,所有的列表推导式都可以转化成生成器表达式,只需要把中括号换成小括号就OK,就是辣么简单~~~

一般情况下,建议都把列表推导式转化成生成器表达式,从而可以节省内存。

 

最后,附:

当把执行生成器的next换成send时,会传入生成器内值,此传入的值需要被接收,否则没啥用,若莫名其妙接收但没有传入值,接收的就是None

send和next工作的起止位置完全一样,在生成器开始执行的时候,必须要先next启动一下

若想send接收成功,需要在生成器中还有一个未被返回的yield

生成器预激装饰器:

def wrapper(func):
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

 

posted @ 2017-09-04 15:55  刘钊up  阅读(56)  评论(0)    收藏  举报