您的位置:澳门402永利com > 编程应用 > Python生成器

Python生成器

发布时间:2019-09-23 20:45编辑:编程应用浏览(169)

    咋样是生成器

    透过列表生成式,我们得以直接创设叁个列表。不过,受到内部存款和储蓄器限制,列表体量肯定是个别的。何况,成立叁个蕴涵100万个因素的列表,不止占用十分大的存款和储蓄空间,要是大家只有须要拜访前边多少个元素,那背后绝大好些个因素占用的长空都白白浪费了。所以,固然列表成分得以依据某种算法推算出来,那我们是还是不是足以在循环的进程中不仅仅推算出后续的要素呢?那样就不用创立完整的list,进而节省大量的半空中。在Python中,这种单方面循环一边企图的体制,称为生成器:generator。

    哪些是生成器
      通过列表生成式,大家得以直接成立二个列表。不过,受到内部存款和储蓄器限制,列表体积确定是有限的。何况,创立二个包蕴100万个要素的列表,不止占用非常的大的囤积空间,假设大家无非需求拜候前边多少个成分,那背后绝大相当多因素占用的空中都白白浪费了。所以,如若列表元素得以遵照某种算法推算出来,那大家是或不是足以在循环的长河中不断推算出后续的成分呢?那样就不要创设完整的list,进而节省大量的空中。在Python中,这种单方面循环一边盘算的机制,称为生成器:generator。

    创制生成器方法

    要成立贰个生成器,有很八种方法。

    首先种办法很轻松,只要把三个列表生成式的 [ ] 改成

    L = [ x*2 for x in range]

    print

    结果

    [0, 2, 4, 6, 8]
    

    将[]改成()

    G = ( x*2 for x in range
    

    结果

    <generator object <genexpr> at 0x7f626c132db0>
    

    怎么打字与印刷出生成器的每三个要素呢?假使要五个一个打字与印刷出来,能够由此 next() 函数得到生成器的下贰个重返值

    生成器保存的是算法,每趟调用 next ,就总计出 G 的下二个要素的值,直到总括到终极多个因素,未有越来越多的因素时,抛出 StopIteration 的不胜。当然,这种持续调用 next() 实在是太变态了,准确的方法是利用 for 循环,因为生成器也是可迭代对象。所以,大家创制了一个生成器后,基本上永世不会调用 next() ,而是通过 for 循环来迭代它,而且无需关心 StopIteration 分外。

    其次种格局

    def fib:

      n = 0

      while n<times:

        yield n

        n += 1

    for i in fib:

      print

    结果:

    0

    1

    2

    3

    4

    5

    6

    7

    8

    9

    a = list(range(10))
    list()把里面的参数转化成列表
    range(10)  range(0,10)
    >>> a = list(range(10))
    >>> a
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> range(10)
    range(0, 10)
    >>>
    

    总结

    生成器是如此二个函数,它记住上三遍回到时在函数体中的地点。对生成器函数的第贰遍调用跳转至该函数中间,而上次调用的具备片段变量都保持不变。

    生成器不独有“记住”了它多少状态;生成器还“记住”了它在流动调查控构造(在命令式编制程序中,这种结构不只是数据值)中的地方。

    生成器的性状:

    1. 节省里部存款和储蓄器

    2. 迭代到下一遍的调用时,所采取的参数都是首先次所保留下的,便是说,在全路全部函数调用的参数都以首先次所调用时保留的,并非新创立的

    创设生成器方法1
    要创造二个生成器,有很两种格局。第一种艺术很简短,只要把一个列表生成式的 [ ] 改成 ( )

    >>> a = (b for c in range(10))
    >>> a
    <generator object <genexpr> at 0x0378DEA0>
    >>> [i for i in range(10)]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> b = [i for i in range(10)]
    >>> b
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>>
    

    创办 L 和 G 的分别仅在于最外层的 [ ] 和 ( ) , L 是叁个列表,而 G 是二个生成器。大家得以一向打字与印刷出L的每三个要素,但大家怎么打字与印刷出G的每一个因素呢?若是要三个四个打字与印刷出来,可以通过 next() 函数得到生成器的下一个再次回到值:

    In [19]: next(G)
    Out[19]: 0
    
    In [20]: next(G)
    Out[20]: 2
    
    In [21]: next(G)
    Out[21]: 4
    
    In [22]: next(G)
    Out[22]: 6
    
    In [23]: next(G)
    Out[23]: 8
    
    In [24]: next(G)
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-24-380e167d6934> in <module>()
    ----> 1 next(G)
    
    StopIteration:
    
    In [25]:
    In [26]: G = ( x*2 for x in range(5))
    
    In [27]: for x in G:
       ....:     print(x)
       ....:    
    0
    2
    4
    6
    8
    

    生成器保存的是算法,每便调用 next(G) ,就总结出 G 的下三个要素的值,直到总结到终极一个因素,没有更加的多的要素时,抛出 StopIteration 的不得了。当然,这种无休止调用 next() 实在是太变态了,准确的艺术是利用 for 循环,因为生成器也是可迭代对象。所以,大家成立了二个生成器后,基本上永久不会调用 next() ,而是通过 for 循环来迭代它,并且不需求关怀 StopIteration 十分。

    创建生成器方法2
    generator特别强劲。假设推算的算法相比复杂,用邻近列表生成式的 for 循环无法完毕的时候,还是能够用函数来完结。
    比如,著名的斐波拉契数列(Fibonacci),除第二个和第二个数外,任性三个数都可由前四个数相加获得:
    1, 1, 2, 3, 5, 8, 13, 21, 34, ...
    斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很轻便:

    In [28]: def fib(times):
       ....:     n = 0
       ....:     a,b = 0,1
       ....:     while n<times:
       ....:         print(b)
       ....:         a,b = b,a+b
       ....:         n+=1
       ....:     return 'done'
       ....://函数没有返回值,用户无法的到这个数列    内存开销太大
    
    In [29]: fib(5)
    1
    1
    2
    3
    5
    Out[29]: 'done'
    

    留神察看,能够看到,fib函数实际上是概念了斐波拉契数列的推算法则,能够从第三个成分开端,推算出后续自便的因素,这种逻辑其实非常邻近generator。
    也正是说,上边的函数和generator仅一步之遥。要把fib函数形成generator,只供给把print(b)改为yield b就足以了:

    In [30]: def fib(times):
       ....:     n = 0
       ....:     a,b = 0,1
       ....:     while n<times:
       ....:         yield b
       ....:         a,b = b,a+b
       ....:         n+=1
       ....:     return 'done'
       ....: //函数没有返回值,用户无法的到这个数据
    
    In [31]: F = fib(5)
    
    In [32]: next(F)
    Out[32]: 1
    
    In [33]: next(F)
    Out[33]: 1
    
    In [34]: next(F)
    Out[34]: 2
    
    In [35]: next(F)
    Out[35]: 3
    
    In [36]: next(F)
    Out[36]: 5
    
    In [37]: next(F)
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-37-8c2b02b4361a> in <module>()
    ----> 1 next(F)
    
    StopIteration: done
    

    在地点fib 的例证,大家在循环进度中连连调用 yield ,就可以随处中断。当然要给循环设置二个尺度来退出循环,不然就能爆发八个极致数列出来。同样的,把函数改成generator后,大家大致没有会用 next() 来博取下一个重临值,而是径直利用 for 循环来迭代:

    In [38]: for n in fib(5):
       ....:     print(n)
       ....:    
    1
    1
    2
    3
    5
    
    In [39]:
    

    但是用for循环调用generator时,开掘拿不到generator的return语句的再次回到值。假若想要得到重回值,必得捕获StopIteration错误,再次回到值满含在StopIteration的value中:

    In [39]: g = fib(5)
    
    In [40]: while True:
       ....:     try:
       ....:         x = next(g)
       ....:         print("value:%d"%x)     
       ....:     except StopIteration as e:
       ....:         print("生成器返回值:%s"%e.value)
       ....:         break
       ....:    
    value:1
    value:1
    value:2
    value:3
    value:5
    

    生成器重返值:done

    In [41]:
    
    send
    

    事例:推行到yield时,gen函数成效一时保留,重返i的值;temp接收后一次c.send("python"),send发送过来的值,c.next()等价c.send(None)

    In [10]: def gen():
       ....:     i = 0
       ....:     while i<5:
       ....:         temp = yield i
       ....:         print(temp)
       ....:         i+=1
       ....:
    

    使用next函数

    In [11]: f = gen()
    
    In [12]: next(f)
    Out[12]: 0
    
    In [13]: next(f)
    None
    Out[13]: 1
    
    In [14]: next(f)
    None
    Out[14]: 2
    
    In [15]: next(f)
    None
    Out[15]: 3
    
    In [16]: next(f)
    None
    Out[16]: 4
    
    In [17]: next(f)
    None
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-17-468f0afdf1b9> in <module>()
    ----> 1 next(f)
    
    StopIteration:
    

    使用next()方法,等同于next(f)

    In [18]: f = gen()
    
    In [19]: f.__next__()
    Out[19]: 0
    
    In [20]: f.__next__()
    None
    Out[20]: 1
    
    In [21]: f.__next__()
    None
    Out[21]: 2
    
    In [22]: f.__next__()
    None
    Out[22]: 3
    
    In [23]: f.__next__()
    None
    Out[23]: 4
    
    In [24]: f.__next__()
    None
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-24-39ec527346a9> in <module>()
    ----> 1 f.__next__()
    
    StopIteration:
    

    使用send

    In [43]: f = gen()
    
    In [44]: f.__next__()
    Out[44]: 0
    
    In [45]: f.send('haha')
    haha
    Out[45]: 1
    
    In [46]: f.__next__()
    None
    Out[46]: 2
    
    In [47]: f.send('haha')
    haha
    Out[47]: 3
    
    In [48]:
    

    达成多任务
    仿照多职分(进度,线程,协程)达成方式之一:协程

    def test1():
        while True:
            print("--1--")
            yield None
    
    def test2():
        while True:
            print("--2--")
            yield None
    
    
    t1 = test1()
    t2 = test2()
    while True:
        t1.__next__()
        t2.__next__()
    

    总结
      生成器是这般三个函数,它记住上二次回到时在函数体中的地点。对生成器函数的第一回(或第 n 次)调用跳转至该函数中间,而上次调用的具备片段变量都维持不变。
    生成器不止“记住”了它多少状态;生成器还“记住”了它在流动调查节构造(在命令式编制程序中,这种组织不只是数据值)中的地点。

    生成器的特点:
    1.节本省部存款和储蓄器
    2.迭代到下二遍的调用时,所运用的参数都以首先次所保留下的,正是说,在全路全数函数调用的参数都以首先次所调用时保留的,而不是新创设的

    本文由澳门402永利com发布于编程应用,转载请注明出处:Python生成器

    关键词:

上一篇:没有了

下一篇:Doctrine2基本使用