• python-生成器


    1.列表生成式

    需求:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 要求你把列表里的每个值加1

    方式一:

    >>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> a
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> for index,i in enumerate(a):
    ...     a[index] += 1
    ...
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    方式二:

    a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    a = list(map(lambda x:x+1, a))
    
    print(a)
    # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    方式三: 列表生成式

    >>> a = [i+1 for i in range(10)]
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>>
    

    2.python生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

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

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

    >>> 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 0x000000000261B258>
    

    创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

    我们可以打印generator 中的每个元素 ,next(g)

    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    9
    >>> next(g)
    16
    >>> next(g)
    25
    >>> next(g)
    36
    >>> next(g)
    49
    >>> next(g)
    64
    >>> next(g)
    81
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    generator 保存的是算法,每次调用next(g)计算并返回每个元素值,,直到最后一个元素后再next(g),会报StopIteration 的错;

    因为generator是可迭代对象,所以我们可以使用 for 循环来处理:

    >>> g = (x*x for x in range(10))
    >>> for i in g:
    ...     print(i)
    ...
    0
    1
    4
    9
    16
    25
    36
    49
    64
    81
    >>>
    

    我们可以看到,for循环 g 不会在最后报错


    其实,range() 就是一个生成器

    >>> range(1000000000)
    range(0, 1000000000)
    >>>
    

    range(1000000000) 后,并没有打印出生成的列表,而是生成了一个公式算法,并没有生成这个列表,在我们真正使用的时候才会不断生成,当然这是在python3 中。

    在python2中,range(10) 后,会把列表直接打印出来,但是python2.7中有一个 xrange(10) ,和python3中的 range()是一样的


    用函数写一个生成器

    #斐波那契数列
    
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b, end=" ")
            a, b = b, a + b
            n += 1
        return 'done'
    
    fib(10) # 1 1 2 3 5 8 13 21 34 55
    
    

    改动一下,把print改为yield

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print("bofore yield......")
            yield b
            print("after yield.......")
            a, b = b, a + b
            n += 1
        return 'done'
    
    f = fib(10)  # turn fuction into a generator
    # 无打印结果,未执行
    
    next(f)  # bofore yield......
    

    next(f)一下,

    next(f)
    next(f)
    

    打印结果:

    # bofore yield......
    # after yield.......
    # bofore yield......
    

    注意:

    • yield b ,把函数的执行过程冻结在这一步,并且把b的值 返回到外面的 next(f),这里可以把函数里面每一步的值返回出来,这一点很有用,在一些场景中可以利用
    • 函数只要加 yidld,函数就会冻结,不再执行,然后生成一个生成器对象

    def range2(n):
    
        count = 0
        while count < n:
            print('count:',count)
            count += 1
            yield count #
        print('------')
        return 'end........'
    
    new_range = range2(3)
    n1 = next(new_range)
    n2 = next(new_range)
    n3 = next(new_range)
    n4 = next(new_range)
    print(n3)
    print(n4)
    

    打印结果:

    Traceback (most recent call last):
      File "D:/Python/python_learning/luffy/code/part2/函数/生成器4.py", line 18, in <module>
        n4 = next(new_range)
    StopIteration: end........
    count: 0
    count: 1
    count: 2
    ------
    

    注意:只要函数中有 yield ,

    1.函数名加() 就得到了一个生成器,

    2.return在生成器中,代表生成器的终止,

    3.在运行到最后的时候,就会报出异常,此时,return的内容会以 StopIteration: end........ 的异常方式反馈


    def range2(n):
    
        count = 0
        while count < n:
            print('count:',count)
            count += 1
            # yield count
            sign_str = yield count
            print('sign_str:',sign_str)
        print('------')
        return 'end........'
    
    new_range = range2(3)
    n1 = next(new_range)
    print("do someting else...")
    new_range.send("stop")
    

    打印:

    count: 0
    do someting else...
    sign_str: stop
    count: 1
    

    1.send,唤醒并继续执行

    2.发送一个信息到生成器内部

    我们可以根据send到生成器内部的内容做一些事情,比如:

    def range2(n):
    
        count = 0
        while count < n:
            print('count:',count)
            count += 1
            # yield count
            sign_str = yield count
            if sign_str == 'stop':
                break
        return 'end........'
    
    new_range = range2(3)
    n1 = next(new_range)
    print("do someting else...")
    new_range.send("stop")
    

    打印:

    Traceback (most recent call last):
      File "D:/Python/python_learning/luffy/code/part2/函数/生成器6.py", line 19, in <module>
        new_range.send("stop")
    StopIteration: end........
    count: 0
    do someting else...
    

    newt(new_range) 实际上是发了一个 'None' 到生成器内部

  • 相关阅读:
    flexbox弹性盒子布局
    LAMP环境 源码包安装
    用条件注释判断浏览器版本,解决兼容问题
    事件冒泡和事件捕获
    为js和css文件自动添加版本号
    uEditor独立图片上传
    修改netbeans模版头部的说明
    thinkphp多表关联并且分页
    thinkphp 独立分组配置
    荣耀路由HiLink一键组网如何实现?
  • 原文地址:https://www.cnblogs.com/friday69/p/9246483.html
Copyright © 2020-2023  润新知