一周一个Python语法糖:(二)迭代器与生成器

迭代器(iterator):

  • 遍历类序列对象的方法
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。
  • 迭代器不能回退,只能往前进行迭代
  • 迭代器也不是线程安全的,在多线程环境中对可变集合使用迭代器是一个危险的操作。
  • 迭代器的另一个优点就是它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazy evaluation)。

惰性计算想像成水龙头,需要的时候打开,接完水了关掉,这时候数据流就暂停了,再需要的时候再打开水龙头,这时候数据仍是接着输出,不需要从头开始循环

1. 迭代器的生成

iter()函数 构造一个迭代器,接受的参数是列表,字典,string 等可迭代的参数

iter1=iter(range(4))
iter1.next()#python2
next(iter1)#python3
工作流程

总不能每次都调用next 去获取值吧(

itertest=iter(range(4))
try:
    while True:
        print(itertest.next())
except StopIteration:
    pass

语法糖:for in

itertest=iter(range(4))
for i in itertest:
    print(i)

当需要知道迭代的索引(通俗讲就是’数组下标‘)的时候,可以用python内置的enmumerate():

for index,value in enumerate(iter1):
        #doSomething()

但是,为何不直接用 :

for i in range(4):
    print(i)

这只是简单的迭代器,当你去做一个无法用列表表达式生成的复杂迭代器的时候,你就需要用自定义的迭代器,然后进行迭代了

2. 自定义迭代器:

迭代器的实现需要实现迭代器协议:

  • 实现了方法 __iter__(),返回一个迭代对象,这个对象有一个next()方法
  • 实现__next()__方法,返回当前元素,并指向下一个元素的位置,
    当前位置已经没有元素的时候,抛出StopIteration异常。
class Iter(object):
    def __init__(self,n):
        self.i=0
        self.n=n
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.i< self.n:
            self.i+=1
            return self.i
        else:
            raise StopIteration()
iter1=Iter(5)
print(next(iter1))
print(next(iter1))
print(next(iter1))
#out  1
#out  2
#out  3

生成器与yield语法

(迭代器这么简单,算语法糖吗?!!)
不急,这才是我们的重头菜!
普通的函数:

函数只有一次返回结果的机会,因而必须一次返回所有的结果。

当我们遇到异步io等问题的时候,我们面临的场景:

  • 网络阻塞,cpu一直卡在这(多线程可以等一会儿)
  • 不阻塞,直接得到结果

结果二当然是我们理想的,结果一好像也可以用多线程去解决
但是,多线程wait的时候进程蹦了呢~,那我们就一无所获了
我可以不可以:
网络io的时候得到一部分就返回一部分内容呢?

这就需要生成器了!!

一个生成器函数的定义很像一个普通的函数,除了当它要生成一个值的时候,使用yield关键字而不是return。如果一个def的主体包含yield,这个函数会自动变成一个生成器(即使它包含一个return)。
生成器函数返回生成器的迭代器

定义生成器:

def simple_generator_function():
    yield '1'
    yield '2'
    yield '3'

为了从生成器获取下一个值,我们使用next()函数,就像对付迭代器一样

#我们在解释器中进行这段代码方便看next()值
>>> our_generator = simple_generator_function()
>>> next(our_generator)
'1'
>>> next(our_generator)
'2'
>>> next(our_generator)
'3'

生成器执行流程:

  • 当调用生成器函数的时候,函数只是返回了一个生成器对象,并没有 执行。
  • 当next()方法第一次被调用的时候,生成器函数才开始执行,执行到yield语句处停止
  • next()方法的返回值就是yield语句处的参数(yielded value)
  • 当继续调用next()方法的时候,函数将接着上一次停止的yield语句处继续执行,并到下一个yield处停止;如果后面没有yield就抛出StopIteration异常

生成器是可以迭代的,但是你只可以读取它一次,因为它并不把所有的值放到内存,而是实时生成的数据

我们来看个简单的列子吧:
当我们需要知道斐波那契数列:
我们通常通过迭代关系获取整个列表(我学C语言的时候就是开整个大数组再去迭代,或者直接递归得到)

def fiblist(n):
    a = b = 1
    result = []
    for i in range(n):
        result.append(a)
        a, b = b, a + b
    return result

对,没毛病~
但是,以下代码不妨一试:(记得开内存查看器)

for x in fiblist(100000):
    print(x)

(我只试了下100000~~~~~炸得飞起)

来来来,优化下:
我们用生成器来做一下:斐波那契数列

def fib(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b

瞬间 就优雅起来~~~~~ 起码我的内存消耗降下来了~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容