• 生成器


    一.生成器

      生成器的实质就是迭代器

    1.1 获取方式

      1.通过生成器函数

      2.通过各种推导式来实现生成器

      3.通过数据的转化也可以获取

     

    简单的函数一目了然
    
    def fun()
        print()
        return 222
    
    ret = fun()
    print (ret)
    
    
    输出结果
    
    111
    222

    将函数中的return换成yied就是生成器

    def fun():
      print("111")
      yied 222
    ret = func()
    print()

    结果:
    <generator object func at 0x10567ff68>

     运行结果是一个地址为什么呢??

    想一想迭代器的惰性要使用__next__来去执行

    def func():
        print("111")
        yield 222
    gener = func() # 这个时候函数不不会执⾏行行. ⽽而是获取到⽣生成器器
    ret = gener.__next__() # 这个时候函数才会执⾏行行. yield的作⽤用和return⼀一样. 也是返回
    数据
    print(ret)
    结果:
    111
    222

     

     我们可以看出yied 的作用和return 有点相似那么她俩的去别是就是return是直接退出,而yied是继续进行遇到下一个yied 的时候继续执行

    def func():
      print("111")
      yield 222
      print("333")
      yield 444
    gener = func()
    ret = gener.__next__()
    print(ret)
    ret2 = gener.__next__()
    print(ret2)
    ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也就是
    说. 和return⽆无关了了.
    print(ret3)
    结果:
    111
    Traceback (most recent call last):
    222
    333
    File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in
    <module>
    444
    ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也
    就是说. 和return⽆无关了了.
    StopIteration

     

    生成器的作用

      生成器在编程中有什么作用呢?假如你要调用一个庞大的数据那么如果你一次性掉出来的时候会撑爆内存的

    所以这个时候用yield 就会变得很容易的, 我们可以分批去调用

      接下来我们来介绍一个send 的用法

    def eat():
      print("我吃什什么啊")
      a = yield "馒头"
      print("a=",a)
      b = yield "⼤大饼"
      print("b=",b)
      c = yield "⾲韭菜盒⼦子"
      print("c=",c)
      yield "GAME OVER"
    gen = eat() # 获取⽣生成器器
    ret1 = gen.__next__()
    print(ret1)
    ret2 = gen.send("胡辣汤")
    print(ret2)
    ret3 = gen.send("狗粮")
    print(ret3)
    ret4 = gen.send("猫粮")
    print(ret4)

    输出的结果

    我吃什什么啊
    馒头
    a= 胡辣汤
    ⼤大饼
    b= 狗粮
    ⾲韭菜盒⼦子
    c= 猫粮
    GAME OVER

     

    来区分一下send 和__next()__:

      1.send 和next()都是让生成器向下一次走

      2.send可以给上一个yield的位置传值,不能给最后一个yield发送值.在第一次执行生成器代码时不能使用send()

    注意的一点就是生成器也可以使用for 循环来获取内部的元素:

    def func():
        print(111)
        yield 222
        print(333)
        yield 444
        print(555)
        yield 666
    gen = func()
    for i in gen:
        print(i)
    结果:
    111
    222
    333
    444
    555
    666    

     

    二 .列表推导式

      这个列表推导式是一个很有技术含量的东西,也就是说你要把前面学的遍历的知识搞懂了学推导式就会很容易

    来个例子

    lst = []
    for i in range(1, 15):
        lst.append(i)
    print(lst)
    
    输出结果
    [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
    
    这个大家很熟悉
    但是它还可以有更简便的方法
    列表推导式
    
    lst = [i for i in range(1.15)]
    print(lst) 输出的结果是 [
    1,2,3,4,5,6,7,8,9,10,11,12,13,14]

    结果一样

     

    格式是:lst = ["你想要的结果"+for循环+判断 ]

    对它还可以加判断

    # 获取1-100内所有的偶数
    lst = [i for i in range(1, 100) if i % 2 == 0]
    print(lst)
    输出的结果
    [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

     

    那么除了列表推导式是不是还有字典推导式

    对!!

    字典推导式跟列表推导式一样不过格式不一样 

    举个例子

    dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"}
    d = {v : k for k,v in dic.items()}
    print(d)
    
    输出的结果是
    
    {'林俊杰': 'jj', '周杰伦': 'jay', '赵四': 'zs', '刘能': 'ln'}

     

     这样是不是会很简单呢.

    那么接下来是不是就应该是元组的推导式呢,其实呢元组的表达式就是生成器的推导式元组是没有推导式的

    来举个例子你就明白了,有些人那就是不见棺材不落泪

    tu = (i for i in range(10)) # 没有元组推导式.  生成器表达式
    print(tu) # 生成器
    
    输出的结果是什么??
    
    <generator object <genexpr> at 0x000001E9AE8359E8>

    是不是跟你想想的不太一样 给你说了元组没有推导式 就是不相信邪

     

    我们把上面的这个表达式叫做生成器的表达式

    tu = (i for i in range(10)) 
    print(tu) 
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    print(tu.__next__())
    
    输出的结果是
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

     

     

    同样生成器的推导式也可以作for 循环还有判断  举个例子

    100以内能被3整除的数的平⽅方
    gen = (i * i for i in range(100) if i % 3 == 0)
    for num in gen:
        print(num)
    
    
    输出结果
    
    0
    9
    36
    81
    144
    225
    324
    441
    576
    729
    900
    1089
    1296
    1521
    1764
    2025
    2304
    2601
    2916
    3249
    3600
    3969
    4356
    4761
    5184
    5625
    6084
    6561
    7056
    7569
    8100
    8649
    9216
    9801

     

    总结一下

    生成器表达式和列表推导式的区别:

    1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存.使用的时候猜分配和使用内存.

    2.得到的值不一样.列表推导式得到的是一个列表.生成器表达式获取的是一个生成器.

     

    举个例子 (很经典的例子)
      同样一篮子鸡蛋,列表推导式拿到一篮子的鸡蛋,生成器表达式拿到的是一个老母鸡,需要鸡蛋就给你下鸡蛋你不就省了空间去放鸡蛋

    所以以后你只要记住老母鸡就能想起生成器表达式

      生成器的惰性机制:生成器只有在访问的时候在取值,说白了,你找它要了他在会给你给,你不要他是不会执行的

    深坑----->生成器.要值的时候才拿值.

     

    还有一个就是集合的推导式

      他与前面提到的一样,我们主要利用集合来取重  举个例子

    lst = [1, 1, 4, 6,7,4,2,2]
    s = { el for el in lst }
    print(s)
    
    输出结果
    
    {1, 2, 4, 6, 7}

     

    生成器表达式和列表推导式的区别:

      1.列表推导式比较耗内存,一次性加载.生成器表达式几乎不占内存,使用的时候才分配和使用内存

      2.得到的值不一样,列表推导式得到的是一个列表.生成器表达式得到的是一个生成器.

    生成器的惰性机制:生成器只有在访问的时候才取值.平常不执行.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def func():
        print(111)
        yield 222
    = func()
    # 生成器g
    g1 = (i for in g) # 生成器g1. 但是g1的数据来源于g
    g2 = (i for in g1)    # 生成器g2. 来源g1
    print(list(g))  # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕.
    print(list(g1))  # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据了
    print(list(g2))  # 和g1同理
    结果:
    111
    [222]
    []
    []

      注意:生成器只有在要值的时候才拿值.

    推导式有列表推导式,字典推导式,集合推导式,没有元组推导式.

    生成器表达式可以直接获取生成器对象,也可以进行for循环.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #关于生成器的一个很重要的题
    def add(a, b):
        return + b
    def test():
        for r_i in range(4):
            yield r_i
    = test()
    for in [210]:
        = (add(n, i) for in g)
    print(list(g))
    结果:
    [20212223]

      

  • 相关阅读:
    Anoconda管理Python版本 | Python
    VSCode用以Python开发的配置 | VSCode
    不联网的情况下安装python环境 | Python(转)
    批量按要求修改文件名
    [OpenLayers] 控件系列之SelectFeature同时支持hover与click
    python使用suds调用webservice接口
    【转载】eMBMS知识点汇总(概念/应用场景/工作原理/标准进程/发展现状)
    处理器分类
    3GPP Release 4G-5G 演进
    浅谈css中一个元素如何在其父元素居中显示
  • 原文地址:https://www.cnblogs.com/RootEvils/p/9467543.html
Copyright © 2020-2023  润新知