zoukankan      html  css  js  c++  java
  • python中的迭代器和生成器学习笔记总结

    生成器就是一个在行为上和迭代器非常类似的对象.   是个对象!

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

    迭代器就是用于迭代操作(for 循环)的对象。它像列表一样可以迭代获取其中的每一个元素,任何实现了 __next__ 方法(python2 是 next)的对象都可以称为迭代器。

    它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(call by need 的方式),本质上 for 循环就是不断地调用迭代器的next方法。

    我们自定义一个迭代器,以斐波那契数列为例:

    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]

    Fib既是一个可迭代对象(因为它实现了 __iter__方法)又是一个迭代器(因为实现了 __next__方法)。实例变量 prev和 curr用户维护迭代器内部的状态。每次调用 next()方法的时候做两件事:

    为下一次调用 next()方法修改状态

    为当前这次调用生成返回结果

    迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

     

    生成器

    然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象,生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁

    关系

    生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写 __iter__()和 __next__()方法了,只需要一个 yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值

    如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)

    要创建一个generator,有很多种方法:

    1.只要把一个列表生成式的[]改成(),就创建了一个generator,又叫生成器表达式(generator expression)

    >>> L = [x * x for x in range(10)]

    >>> L

    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    >>> g = (x * x for x in range(10))

    >>> g

    <generator object <genexpr> at 0x104feab40>

    打印出generator的每一个元素呢?

    如果要一个一个打印出来,可以通过generator的next()方法:

    >>> g.next()

    0

    >>> g.next()

    1

    >>> g.next()

    4

    ......

    不断调用next()方法实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象

    >>> g = (x * x for x in range(10))

    >>> for n in g:

    ...     print n

    ...

    0

    1

    4

    9

    16

    25

    36

    49

    64

    81

    2.如果推算的算法比较复杂,可以用函数来实现

    如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator.

    最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

    举个简单的例子(很清楚了),定义一个generator,依次返回数字1,3,5:

    >>> def odd():

    ...     print 'step 1'

    ...     yield 1

    ...     print 'step 2'

    ...     yield 3

    ...     print 'step 3'

    ...     yield 5

    ...

    >>> o = odd()  ----->返回的是一个生成器对象,此时函数体中的代码并不会执行,只有显示或隐示地调用next的时候才会真正执行里面的代码。

    >>> o.next()

    step 1

    1

    >>> o.next()

    step 2

    3

    >>> o.next()

    step 3

    5

    >>> o.next()

    Traceback (most recent call last):

      File "<stdin>", line 1, in <module>

    StopIteration

    可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用nex

    把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:

    例子:比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

    (1)用函数实现:

    def fib(max):

        n, a, b = 0, 0, 1

        while n < max:

            print b

            a, b = b, a + b

            n = n + 1

    输出:

    >>> fib(6)

    1

    1

    2

    3

    5

    8

    (2)要把fib函数变成generator,只需要把print b改为yield b就可以了:

    def fib(max):

        n, a, b = 0, 0, 1

        while n < max:

            yield b

            a, b = b, a + b

            n = n + 1

    输出:

    >>> fib(6)

    <generator object fib at 0x104feaaa0>

    把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:

    >>> for n in fib(6):

    ...     print n

    ...

    1

    1

    2

    3

    5

    8

  • 相关阅读:
    实验10 使用PBR实现策略路由
    实验9 使用route-policy控制路由
    实验8 filter-policy过滤路由
    实验7 ISIS多区域配置
    实验6 IS-IS基本配置
    MySQL复制表
    mysql数据备份
    mysql 创建用户,授权
    数据库
    mysql 修改文件记录:
  • 原文地址:https://www.cnblogs.com/christychang/p/6550033.html
Copyright © 2011-2022 走看看