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

    一. 生成器

    什么是⽣成器. 生成器实质就是迭代器. 在python中有三种⽅式来获取⽣成器:

    1. 通过生成器函数
    2. 通过各种推导式来实现⽣成器
    3. 通过数据的转换也可以获取⽣成器

    首先, 我们先看一个很简单的函数:

    def func():
        print("111")
        return 222
    ret = func()
    print(ret)
    
    结果: 111 222
    
    将函数中的return换成yield就是生成器
    
    def func(): print("111")
        yield 222
        ret = func()
    print(ret)
    
    结果:
    <generator object func at 0x10567ff68>
     

    运行的结果和上面不⼀样. 为什么呢. 由于函数中存在了了yield. 那么这个函数就是一个生成器函数. 这个时候. 我们再执行这个函数的时候. 就不再是函数的执行了. ⽽是获取这个生成器. 如何使用呢? 想迭代器. ⽣成器的本质是迭代器. 所以. 我们可以直接执行__next__()来执行

    以下⽣生成器.

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

    那么我们可以看到, yield和return的效果是一样的. 有什区别呢? yield是分段来执⾏行行⼀一个 函数. return呢? 直接停⽌止执⾏行行函数.

     

    接下来我们来看send方法, send和__next__()⼀样都可以让生成器执行到下一个yield.

    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)
     

    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

    ⼆. 列表推导式, ⽣成器表达式以及其他推导式 ⾸先我们先看⼀下这样的代码, 给出一个列表, 通过循环, 向列表中添加1-13 :替换成列表推导式:

    列表推导式是通过⼀行来构建你要的列表, 列表推导式看起来代码简单. 但是出现错误之后很难排查.
    列表推导式的常⽤写法:

    [ 结果 for 变量量 in 可迭代对象]
    例. 从python1期到python14期写入列列表lst:

    lst = [] 
    for i in range(1, 15):
        lst.append(i)
    
    print(lst)
    
    lst = [i for i in range(1, 15)]
    print(lst)
    
    lst = ['python%s' % i for i in range(1,15)]
    print(lst)

    筛选模式:
    [ 结果 for 变量量 in 可迭代对象 if 条件 ]

    ⽣成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()

    打印的结果就是一个生成器. 我们可以使用for循环来循环这个生成器:

    # rst = [x for x in "abc"]
    #
    # print(rst)
    #
    # lst1 = ["中岛美雪", "夏川美里", "原由子", "汪峰", "田震", "那英", "周杰伦"]
    #
    # lst2 = [x for x in lst1 if len(x) < 3]
    #
    # print(lst2)
    #
    # lst3 = [x * x for x in range(1, 21) if x % 2 == 1]
    #
    # print(lst3)
    #
    # lst4 = [3, 6, 9]
    #
    # lst5 = [(x - 2, x - 1, x) for x in lst4]
    #
    # print(lst5)
    #
    # lst6 = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
    #         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    #
    # lst7 = [j for i in lst6 for j in i if j.count("l") == 2]
    #
    # print(lst7)
    #
    # lst8 = {"张无忌": "赵敏", "杨过": "小龙女", "郭靖": "黄蓉"}
    #
    # lst9 = {v: k for k, v in lst8.items()}
    #
    # print(lst9)
    #

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

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

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

    ⽣成器的惰性机制: ⽣成器只有在访问的时候才取值. 说白了. 你找他要他才给你值. 不找他要. 他是不会执⾏的.

    # def abc():
    #     print("-->",111)
    #     yield 222
    #     yield  333
    #
    # g = abc()
    # g1 = (x for x in g)
    # g2 = (x for x in g1)
    #
    #
    # print("g =", list(g))
    #
    # print("g1 =", list(g1))
    #
    #
    # print("g2 =", list(g2))
    

      

    总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 生成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选) ⽣成器表达式可以直接获取到生成器对象. 生成器对象可以直接进行for循环. ⽣成器具有惰性机制.

    一个⾯面试题. 难度系数500000000颗星:

    def add(a, b): 
        return a + b
    
    def test():
        for r_i in range(4):
            yield r_i
    
    g = test()
    
    for n in [2, 10]: g = (add(n, i) for i in g)

    """
      此处要注意,此处g这个生成器表达式在循环的时候并没有调用,只在最后的print才调用了,此处可以理解为:循环的时候,生成器表达式并没有执行,第一次循环n2=的时候
      g = (add(n, i) for i in g) 这个生成器表达式的代码没有执行只是拷贝到一块新的内存中,第二次循环的时候n=10,此时生成器表达式没有执行,
      g = (add(n, i) for i in g) 也拷贝到了内存中。当最后print的时候,n最后的值是10,然后开始执行生成器表达式中的代码。此时
      g = (add(10,i) for i in (add(10,i) for i in g));结果为20,21,22,23.

    """ print(list(g))

      

    友情提示: 惰性机制, 不到最后不会拿值

  • 相关阅读:
    UnityWebgl错误-Uncaught DOMException: Blocked a frame with origin "" from accessing a cross-origin frame
    【Oracle123】v$sql 视图
    【QA123】ISO9126软件质量模型
    【测试工具123】HP LoadRunner
    【CSV123】如何使用Excel打开CSV并保留大数字精度
    【Java123】
    【FRM-Level2】2020 FRM二级考纲变化
    【FRM-Level2】2020 FRM二级 Current Issues
    【Oracle123】Oracle数据导入导出
    【中间件123】消息队列性能对比
  • 原文地址:https://www.cnblogs.com/fanghongbo/p/9891440.html
Copyright © 2011-2022 走看看