python 中的迭代器和生成器详解

迭代器

     学习过python的童鞋都应该知道python中有三大神器,即 迭代器、生成器和装饰器,所谓神器,必有其神奇之处,今天和大家一起学习一下迭代器和生成器。
     迭代是python比较强大的功能之一,说起迭代,我们可能会想到,对于一个列表list,一个元组tuple,访问的时候都可以使用 for .. in .. ,没错,这就是迭代,它是访问集合元素的一种方式,在从头到尾遍历可迭代对象时,能够记住遍历的位置。
     这里给大家区分两个概念 可迭代对象(iterable)和迭代器(iterator), 我们往往说某个对象是不是可迭代的,而迭代器可以抽象为一个‘器’,就是在从头到尾遍历可迭代对象中的某一元素时,能够记住遍历的位置的那玩意儿,二者之间有本质区别,下面举例说明一下

    from collections import Iterable

    test = ['a', 'b']
    for i in test:
        print(i)
    # 输出结果,说明列表是可迭代的
    a
    b

    isinstance([], Iterable)
    True
    
    for i in 10:
        print(i)
    #输出结果,说明整型数字是不可迭代的
    TypeError: 'int' object is not iterable

    isinstance(10, Iterable)
    False

     上面我们看到的是可迭代对象的外在表现,那么可迭代对象的本质又是什么呢?答案就是一个具备iter方法的对象就是可迭代对象,话不多说,上代码看一下

    from collections import Iterable
    class MyIter():
        def __init__(self):
            pass

        def __iter__(self):
            pass

    if __name__ == "__main__":
        test = MyIter()
        print(isinstance(test, Iterable))
    # 输出结果
    True   

     上面说过迭代器能够记住可迭代对象属性的位置,其本质是在可迭代对象中加了next()方法(python2中是next()方法),下面手动实现一个迭代器:

    class MyIterator():
        def __init__(self):
            self.test_list = ['Hello', 'I', 'Love', 'python']
            self.position = 0

        def __iter__(self):
            # 要返回一个迭代器,这里返回自身
            return self
        
        def __next__(self):
            # 该方法的主要作用记录迭代输出位置
            if self.position < len(self.test_list):
                ret = self.test_list[self.position]
                self.position += 1
                return ret
            # 当超出列表长度的时候,抛出停止迭代的异常
            else:
                raise StopIteration

    if __name__ == "__main__":
        test = MyIterator()
        for i in test:
            print(i, end=' ')
    # 输出结果
    Hello I Love python

     总结一下,判断一个对象是不是可迭代的,就看该对象有没有实现iter()方法,要判断一个对象是不是迭代器,就看该对象有没有实现iter()方法和next()方法。我们平时用的比较多的for .. in ..循环,其执行过程的本质就是通过iter()获取一个可迭代对象,然后通过该调用对象的next()方法获取下一个值,知道满足停止迭代的条件之后,抛出停止迭代的异常,然后停止循环。

生成器

     生成器(generator)是一种的特殊的迭代器,其特殊之处在于我们可以根据需要生成数据,生成器的创建方式有两种,第一种比较简单,将列表推导式的[]换成()就是生成器.

    In [3]: a = [x**2 for x in range(5)]
    In [4]: a
    Out[4]: [0, 1, 4, 9, 16]

    In [5]: b = (x**2 for x in range(5))
    In [6]: b # b是一个生成器对象
    Out[6]: <generator object <genexpr> at 0x000001E45FF01B88>
    # 生成器具有__next__()方法
    In [7]: b.__next__()
    Out[7]: 0
    In [8]: b.__next__()
    Out[8]: 1

     第二种方式就是通过使用yield创建生成器,一个函数,只要里面含有yield,那么它一定就是生成器,下面写个简单的代码说明一下通过yield创建的生成器。

    def my_generator():
        i = 0
        print("1111111")
        while i<5:
            yield i
            i += 1
            print("22222")
        print("33333")

    if __name__ == "__main__":
        gg = my_generator()
        print(gg)
        # 输出 <generator object my_generator at 0x0000023DECA9BA20>
        print(gg.__next__())
        # 1111111
        # 0
        print(gg.__next__())
        # 22222
        # 1
        print(gg.__next__())
        # 22222
        # 2

     简述一下上面代码执行的流程:函数执行到第一步(gg=my_generator())的时候,python编译器发现函数中有yield,将这个函数定义为一个生成器,于是实例化gg为一个生成器对象,上面说过,生成器是一个特殊的迭代器,通过第一次调用next()方法,函数从上往下执行,当执行到yield的时候,将yield 后的对象(0)返回,当第二次调用next()方法的时候,会接着yield i继续往下执行,所以先打印22222,执行到yield的时候,将yield 后的对象(1)返回,以此类推。
     讲到yield,总避免不了一个话题,那就是yield与return的对比,二者都能结束函数的运行,他们的区别主要是return 之后,函数下次执行只能从头开始执行,而yield 能够接着继续执行,这就是二者主要区别。

文章转自 https://www.cnblogs.com/study-666/

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

推荐阅读更多精彩内容