zoukankan      html  css  js  c++  java
  • 生成器

    迭代器:

    比方说一个数列,你将其遍历一遍就称之为迭代。这个数列就称之为迭代对象。迭代对象可以是字符可以是数列。

    生成器:  

     
    数列的存储空间是有限的。如果数列的值可以通过算法来实现,那么这种通过算法来实现数列值的机制称之为"生成器(Generator)"

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    1 >>> L = [x * x for x in range(10)]
    2 >>> L
    3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    4 >>> g = (x * x for x in range(10))
    5 >>> g
    6 <generator object <genexpr> at 0x104feab40>

    来源: https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138681965108490cb4c13182e472f8d87830f13be6e88000
    如何使用直接使用next()即可

     1 >>> l.next()
     2 0
     3 >>> l.next()
     4 1
     5 >>> l.next()
     6 4
     7 >>> l.next()
     8 9
     9 >>> l.next()
    10 16
    11 >>> l.next()
    12 25
    13 >>> l.next()
    14 36
    15 >>> l.next()
    16 49
    17 >>> l.next()
    18 64
    19 >>> l.next()
    20 81
    21 >>> l.next()
    22 Traceback (most recent call last):
    23 File "<stdin>", line 1, in <module>
    24 StopIteration

    当没有的时候就会抛出StopIteraction错误
    我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它

     1 >>> s = (x*x for x in range(10))
     2 >>> for i in s:
     3 ...     print i
     4 ...
     5 0
     6 1
     7 4
     8 9
     9 16
    10 25
    11 36
    12 49
    13 64
    14 81

    用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
    比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

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

    斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    1 def fib(max):
    2    n, a, b = 0, 0, 1
    3    while n < max:
    4        print b
    5        a, b = b, a + b
    6        n = n + 1

    上面的函数可以输出斐波那契数列的前N个数:

    1 >>> fib(6)
    2 1
    3 1
    4 2
    5 3
    6 5
    7 8

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

    也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

    1 def fib(max):
    2 n, a, b = 0, 0, 1
    3 while n < max:
    4 yield b
    5 a, b = b, a + b
    6 n = n + 1

    #个人认识好像就等同于print没区别似的

    1 >>> def fib(max):
    2 ...    n,a,b = 0,0,1
    3 ...    while n < max:
    4 ...            yield b
    5 ...            a,b = b,a+b
    6 ...            n +=1
    7 ...
    8 >>> fib(6)
    9 <generator object fib at 0x00B73670>

            这里,最难理解的就是generator和函数的执行流程不一样

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



    举个简单的例子,定义一个generator,依次返回数字1,3,5:

     1 >>> def odd():
     2 ... print 'step 1'
     3 ... yield 1
     4 ... print 'step 2'
     5 ... yield 3
     6 ... print 'step 3'
     7 ... yield 5
     8 ...
     9 >>> o = odd()
    10 >>> o.next()
    11 step 1
    12 1
    13 >>> o.next()
    14 step 2
    15 3
    16 >>> o.next()
    17 step 3
    18 5
    19 >>> o.next()
    20 Traceback (most recent call last):
    21 File "<stdin>", line 1, in <module>
    22 StopIteration

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

    回到fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

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

    1 >>> for n in fib(6):
    2 ... print n
    3 ...
    4 1
    5 1
    6 2
    7 3
    8 5
    9 8

    小结

    generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

    要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

  • 相关阅读:
    mybatis-config.xml详解
    过滤器与拦截器
    Tomcat 部署web 项目
    Tomcat架构
    git stash
    AbstractQueuedSynchronizer 源码解读(转载)
    Kafka 转载
    Oracle数据库TNS详解
    Oracle建表知识全面详解
    Oracle高级教程
  • 原文地址:https://www.cnblogs.com/nul1/p/8904335.html
Copyright © 2011-2022 走看看