zoukankan      html  css  js  c++  java
  • 环境小硕的转行之路-16-生成器函数、推导式、生成器表达式

    大纲

        1. 生成器
                生成器的本质就是迭代器
                生成器的特点和迭代器一样(3点).取值方式和迭代器一样(__next__(), send(): 给上一个yield传值).
                生成器一般由生成器函数或者生成器表达式来创建
                其实就是手写的迭代器
    
            2. 生成器函数
                和普通函数没有区别. 里面有yield的函数就是生成器函数.
                生成器函数在执行的时候. 默认不会执行函数体. 会返回生成器。
                通过生成器的__next__(),或者send()分段执行这个函数。
                send() 给上一个yield传值, 不能在开头(没有上一个yield), 最后一个yield也不可以用send()。
    
            3. 推导式
                1. 列表推导式 [结果 for循环 条件筛选]
                2. 字典推导式 {k:v for循环 条件筛选}
                3. 集合推导式 {k for循环 条件}
    
            4. 生成器表达式
                (结果 for循环 条件)
                特点:
                    1. 惰性机制
                    2. 只能向前
                    3. 节省内存(老母鸡生鸡蛋vs买一车鸡蛋) 
    

    生成器

    导入

    def func():
         print('呵呵呵')
         yield 1#return和yield 都可以返回数据
         print('哈哈哈')
     print(func())#返回一堆地址,说明此时不会执行函数,拿到的是生成器
     print(func().__next__())#执行到下一个yield
     ret = func()
     ret.__next__()
     ret.__next__()#Stopiteration因为没有下一个yield了
    yield:相当于return,可返回数据,但是yield不会彻底中断函数,会分段执行函数。
    如果函数中有yield,则此函数变成生成器(本质是迭代器).想执行生成器函数必需__next__(惰性机制),执行yield就执行到下一个yield。
    

    为什么要用生成器

    #不用生成器
    def order():
        lst = []
        for i in range(10001):
            lst.append('衣服'+str(i))
        return lst
    
    ll = order()#衣服放在这里暂时不用占用大量内存,内存很有可能被撑爆.最好来一个人要一件衣服,这样内存不容易被撑爆。
    #用生成器
    def order():
        for i in range(10000):
            yield '衣服'+str(i)
    g = order()#获取生成器
    guest1 = g.__next__()
    guest2 = g.__next__()#这样子几乎不占内存,需要的时候直接生成。
    #send()和__next__一样,执行到下一个yield,可以给上一个yield的位置传值
    def func():
        print('我是第一段')
        a = yield 123#执行含有等号段的的时候先执行等号右边的,见到yield直接跑出去了.第二次跑a->yield 456,此时__next()__没有给a传值,所以a是空的.(NONE)
        print(a)#这里不知道为什么不会打印一个'none'
        print('我是第二段')
        b = yield 456
        print(b)
        print('我是第三段')
        c = yield 789
        print(c)
        print('我是第四段')
        yield 'negu'#生成器函数最后收尾的一定是yield,且不能传值
    y = func()
    print(y.__next__())#因为一开始没有上一个yield,所以必须用__next()__
    print(y.send('嘻嘻'))
    print(y.send('呼呼'))
    print(y.send('湫湫'))
    
    输出:
    我是第一段
    123
    嘻嘻 我是第二段 456 呼呼 我是第三段 789 湫湫 我是第四段

    获得生成器的内部元素

    #生成器可以使用for循环获得其内部的元素
    def shengcheng():
        yield 88
        yield 888
        yield 8888
        yield 88888
    for i in shengcheng():#for的内部一定有__next__
        print(i)
    print(list(shengcheng()))#list内部也有__next__
    

    推导式

    #推导式:用一句话来生成一个列表
    lst = ['python'+str(i) for i in range(1,16)]
    print(lst)
    #语法:[结果+for循环]
    
    lst = [i for i in range(1,100) if i%2 != 0]
    print(lst)
    
    #语法[结果+for循环+判断]
    
    #100以内能被3整除数的平方
    lst = [i**2 for i in range(100) if i%3 == 0]
    print(lst)
    
    # 寻找名字中带有两个e的人的名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven',
    'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    lst = [name for line in names for name in line if name.count('e') == 2]
    print(lst)
    
    #[11,22,33,44]->{0:11,1:22,2:22......}
    lst = [11,22,33,44]
    dict = {k:v for k,v in enumerate(lst)}
    print(dict)
    #语法{k:v for循环 条件筛选}
    
    #调换dict的key和value
    
    dict_1 = {v:k for k,v in dict.items()}
    print(dict_1)
    
    #字典里直接装数据而没有k:v格式则生成一个set
    
    sets = {i for i in range(10)}
    print(sets,type(sets))
    

    生成器+推导式 = 生成器表达式

    gen = ( i for i in range(10))#生成器,惰性机制
    
    def func():
        print(111)
        yield 222
    g = func()#产生了一个生成器
    g1 = (i for i in g)
    g2 = (i for i in g1)
    print(list(g)) #[222] 从源头把数据拿走了
    print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了数据,g1就没有数据了。
    print(list(g2)) #同上,(g1,g2,g内部对生成器取值方式都必须为__next__取值取完就没了。)
    

    地狱训练

    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)
    print(list(g))#全拿出来 结果20,21,22,23
    #解析
    #上面的代码相当于:
    # n = 2
    # g  = (add(n, i) for i in g)#执行n=2的时候,此时没有从生成器中拿过值,n没有往里带。
    # n = 10
    # g  = (add(n, i) for i in add(n, i) for i in g)
    
    #又相当于
    # n = 10
    # g = [0,1,2,3]
    # t  = (add(n, i) for i in (add(n, el) for el in g))
    # print(list(t))
    print(list(g))#全拿出来
    
  • 相关阅读:
    重拾node第一天
    layui采坑记录 (上卷)QUQ
    解决IOS固定定位 fixed的不兼容
    layui 启用禁用切换详解
    jq form表单渲染单选框内容渲染
    vue 工具函数的封装 时间格式化函数
    CSS常见的继承属性
    git简单使用指南
    常用git命令大全
    react项目使用antd
  • 原文地址:https://www.cnblogs.com/negu/p/11510614.html
Copyright © 2011-2022 走看看