zoukankan      html  css  js  c++  java
  • Python之可迭代对象、迭代器、生成器

    在使用Python的过程中,很容易混淆如下几个关联的概念:

    1.容器(container)

    2.可迭代对象(Iterable)

    3.迭代器(Iterator)

    4.生成器(generator)

    5.生成器表达式

    6.{list, set, dict} 解析式

    它们之间的关系如下表所示:

     

    容器(container)

    容器是用来储存元素的一种数据结构,它支持隶属测试,容器将所有数据保存在内存中,在Python中典型的容器有:

    list, deque, …

    set,frozesets,…

    dict, defaultdict, OrderedDict, Counter, …

    tuple, namedtuple, …

    str

    容器相对来说很好理解,因为你可以把它当成生活中的箱子、房子、船等等。
    一般的,通过判断一个对象是否包含某个元素来确定它是否为一个容器。例如:

    字典容器通过检查是否包含键来进行判断:

    字符串通过检查是否包含某个子 串来判断:

    注意:并非所有的容器都是可迭代对象。

    可迭代对象

    正如前面所提到的,大部分容器都是可迭代的,但是还有其他一些对象也可以迭代,例如,文件对象以及管道对象等等,容器一般来说存储的元素是有限的,同样的,可迭代对象也可以用来表示一个包含有限元素的数据结构。

    可迭代对象可以为任意对象,不一定非得是基本数据结构,只要这个对象可以返回一个iterator。听起来可能有点费解,但是可迭代对象与迭代器之间有一个显著的区别。先看下面的例子

    注意:可迭代的类中,一般实现以下两个方法,__iter__()以及__next()__方法,__iter__()方法返回self。

    当我们运行以下代码的时候:

    1

    2

    3

    x = [1,2,3]

    for elem in x:

     ...

    实际调用过程如下:

    当我们反向编译这段代Python码的时候,可以发现它显示调用了 GET_ITER,本质上跟调用iter(x)一样,而FOR_ITER指令相等于调用next()方法来获取每个元素。

    >>> import dis

    >>> x = [1,2,3]

    >>> dis.dis('for _ in x: pass')

      1           0 SETUP_LOOP              12 (to 14)

                  2 LOAD_NAME                0 (x)

                  4 GET_ITER

            >>    6 FOR_ITER                 4 (to 12)

                  8 STORE_NAME               1 (_)

                 10 JUMP_ABSOLUTE            6

            >>   12 POP_BLOCK

            >>   14 LOAD_CONST               0 (None)

                 16 RETURN_VALUE

    迭代器(Iterators)

    那么什么是迭代器呢?任何具有__next__()方法的对象都是迭代器,对迭代器调用next()方法可以获取下一个值。而至于它使如何产生这个值的,跟它能否成为一个迭代器并没有关系。所以迭代器本质上是一个产生值的工厂,每次向迭代器请求下一个值,迭代器都会进行计算出相应的值并返回。

    迭代器的例子很多,例如,所有itertools模块中的函数都会返回一个迭代器,有的还可以产生无穷的序列。

    有的函数根据有限序列中生成无限序列:

    2

    3

    4

    5

    6

    7

    8

    9

    10

    >>> from itertools import cycle

    >>> colors = cycle(["red","white","blue"])

    >>> next(colors)

    "red"

    >>> next(colors)

    "white"

    >>> next(colors)

    "blue"

    >>> next(colors)

    "red"

    有的函数根据无限序列中生成有限序列:

    >>> from itertools import islice

    >>> colors = cycle(['red', 'white', 'blue'])     # infinite

    >>> limited=islice(colors,0, 4)            # finite

    >>> for x in limited:                # so safe to use for-loop on

    ...            print(x)

    red

    white

    blue

    Red

    为了更好的理解迭代器的内部结构,我们先来定义一个生成斐波拉契数的迭代器:

    >>> class fib:

    ...             def __init__(self):

    ...                   self.prev = 0

    ...                   self.curr = 1

    ...

    ...             def __iter__(self):

    ...                   return self

    ...

    ...             def __next__(self):

    ...                   value = self.curr

    ...                   self.curr += self.prev

    ...                   self.prev = value

    ...                   return value

    ...

    >>> f = fib()

    >>> list(islice(f, 0, 10))

    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

    注意这个类既是可迭代的 (因为具有__iter__()方法),也是它自身的迭代器(因为具有__next__()方法)。

    迭代器内部状态保存在当前实例对象的prev以及cur属性中,在下一次调用中将使用这两个属性。每次调用next()方法都会执行以下两步操作:

    修改状态,以便下次调用next()方法

    计算当前调用的结果

    比喻:从外部来看,迭代器就像政府工作人员一样,没人找他办事的时候(请求值),工作人员就闲着,当有人来找他的时候(请求值),工作人员就会忙一会,把请求的东西找出来交给请求的人。忙完之后,又没事了,继续闲着。

    生成器

    生成器其实就是一种特殊的迭代器。它shi一种更为高级、更为优雅的迭代器。
    使用生成器让我们可以以一种更加简洁的语法来定义迭代器。
    让我们先明确以下两点:

    任意生成器都是迭代器(反过来不成立)

    任意生成器,都是一个可以延迟创建值的工厂

    下面也是一个生成斐波那契序列的工厂函数,不过是以生成器的方式编写的:

    生成器的类型

    在Python中两种类型的生成器:生成器函数以及生成器表达式。生成器函数就是包含yield参数的函数。生成器表达式与列表解析式类似。

  • 相关阅读:
    React.js学习笔记之事件系统
    彻底解决Webpack打包慢的问题:npm run build:dll
    gulp详细入门教程
    cmd、node、npm 常用命令
    ant design中ES6写法个人总结
    自定义浏览器滚动条的样式,打造属于你的滚动条风格
    js相关知识
    day31-python阶段性复习五
    day30-python阶段性复习四
    day29-python阶段性复习三
  • 原文地址:https://www.cnblogs.com/Michael-Beechan/p/7098511.html
Copyright © 2011-2022 走看看