• 生成器 推导式


    生成器 推导式

    生成器 Generator

    本质:(就是迭代器)

    • 迭代器(所以自带了(_ iter ) 方法和 ( next _)方法,不需要我们去实现)

    特点:

    • 惰性运算,开发者自定义

    生成器的构建方式

    生成器函数

    ef func():
        print(11)
        yield 22
    ret = func()
    print(ret)  
    # 运行结果:<generator object func at 0x000001A575163888> 生成器
    print(next(ret)) # 22 一个next对应一个yield
    

    生成器推导式(表达式)

    python内置函数或者模块提供

    def func():
         print("111")
         yield 222
         print("333")
         yield 444
    gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器
    ret = gener.__next__() # 这个时候函数才会执⾏
    print(ret)  # 并且yield会将func生产出来的数据 222 给了 ret。  
    ret2 = gener.__next__()
    print(ret2)  # 最后⼀个yield执⾏完毕. 再次__next__()程序报错,与迭代器一样。
    #  打印结果: 111
                222
                333
                444
    

    return 与 yield的区别

    return

    • 一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。

    yield

    • 在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。
    • 一个yield有多个值以 元组 返回

    生成器的作用:节省内存

    send 方法(了解)

    send注意事项

    • 第一次使用生成器的时候 是用next获取下一个值
    • 最后一个yield不能接受外部的值
    # next只能获取yield生成的值,但是不能传递值。
    def gen(name):
        print(f'{name} ready to eat')
        while 1:
            food = yield
            print(f'{name} start to eat {food}')
    dog = gen('alex')
    next(dog)
    next(dog)
    next(dog)
    
    # 而使用send这个方法是可以的。
    def gen(name):
        print(f'{name} ready to eat')
        while 1:
            food = yield 222
            print(f'{name} start to eat {food}')
    ​
    dog = gen('alex')
    next(dog)  # 第一次必须用next让指针停留在第一个yield后面
    # 与next一样,可以获取到yield的值
    ret = dog.send('骨头')
    print(ret)
    ​
    def gen(name):
        print(f'{name} ready to eat')
        while 1:
            food = yield
            print(f'{name} start to eat {food}')
    dog = gen('alex')
    next(dog)
    # 还可以给上一个yield发送值
    dog.send('骨头')
    dog.send('狗粮')
    dog.send('香肠')
    

    yield from

    # 对比yield 与 yield from 
    def func():
        lst = ['卫龙','老冰棍','北冰洋','牛羊配']
        yield lst
    g = func()
    print(g)
    print(next(g))  # 只是返回一个列表
    ​
    def func():
        lst = ['卫龙','老冰棍','北冰洋','牛羊配']
        yield from lst
    g = func()
    print(g)
    # 他会将这个可迭代对象(列表)的每个元素当成迭代器的每个结果进行返回。
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    '''
    yield from ['卫龙','老冰棍','北冰洋','牛羊配'] 
    等同于:
        yield '卫龙'
        yield '老冰棍'
        yield '北冰洋'
        yield '牛羊配'
    '''
    
    • yield from 是将列表中的每一个元素返回,所以 如果写两个yield from 并不会产生交替的效果
    def func():
        lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
        lst2 = ['馒头', '花卷', '豆包', '大饼']
        yield from lst1
        yield from lst2
    
    
    g = func()
    for i in g:
        print(i)
    # 打印结果 :
    '''
    卫龙
    老冰棍
    北冰洋
    牛羊配
    馒头
    花卷
    豆包
    大饼
    '''
    

    yield 与 yield from 对比

    • yield : 对应next 给 next 一 一 返回值
    • yield from : 将迭代对象的每一个元素返回给 next

    yield from 作用:

    • 节省代码,提升效率(代替了for循环)

    推导式

    列表推导式

    优点 :

    • 简单 快捷

    缺点 :

    • 可读性不高 不好排错
    li = []
    for i in range(1,101):
        li.append(i)
    print(li)
     
    li = [i for i in range(1,101)]  #列表推导式(循环模式)
    print(li)
    

    构建方式

    循环模式:[变量(加工的变量) for 变量 in iterable]

    筛选模式 : [变量(加工的变量) for 变量 in iterable if 条件]

    # 要求做一个列表 1-100
    li = [i for i in range(1,101)]
    print(li)
    # 要求做一个1-10之内的平方和的列表
    li = [i*i for i in range(1,11)]
    print(li)
    # 1-100内 所有的偶数
    li = [i for i in range(1,101) if i % 2 == 0]
    print(li)  # 这个就是筛选模式(有条件判断)
    
    li = [i for i in range(2,101,2)]
    print(li)
    
    # "python1期"到"python100期"的列表
    li = [f'python{i}期' for i in range(1,101)]
    print(li)  # f'python{i}',就是加工的变量
    

    多层列表推导式

    #找到嵌套列表中名字含有两个‘e’的所有名字(有难度)
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    li = []
    for i in names:
        for e in i:
            if e.count("e") > 1:
                li.append(e)
    print(li)
    
    print([e for i in names for e in i if e.count("e") == 2]) # 两层
    

    生成器表达式

    • 节省内存
    • 与列表推导式几乎一模一样,只是把[]换成()就行了

    循环模式

    gen = (i**2 for i in range(10))
    print(gen)
    # 结果: <generator object <genexpr> at 0x0000026046CAEBF8>
    
    

    筛选模式

    # 获取1-100内能被3整除的数
    gen = (i for i in range(1,100) if i % 3 == 0)
    for num in gen:
        print(num) # 打印结果就是for遍历了 所有在gen里的元素
    print(next(gen))  # 要几个打印几个 一次只打印一个 记录位置
    print(*gen) # 横向打印所有的gen里的元素
    print(list(gen))  # 打印一个列表 (list可换成set / tuple / ) 字典除外
    
    

    如何触发生成器(迭代器)取值

    nxet

    for / for i in li print(next(li))

    print(list(obj)) 直接打印出一个列表 转化成容器类型(字典除外) 常用list转化

    print(*obj)

    字典推导式 循环模式 / 筛选模式

    lst1 = ['jay','jj','meet']
    lst2 = ['周杰伦','林俊杰','郭宝元']
    dic = {lst1[i]:lst2[i] for i in range(len(lst1))}    # 两个列表长度必须一样
    print(dic)
    
    

    集合推导式 循环模式 / 筛选模式

    lst = [1,2,3,-1,-3,-7,9]
    s = {abs(i) for i in lst}
    print(s) # 天然去重
    
    

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

    生成器表达式

    • 生成器表达式遵循迭代器协议,逐个产生元素
    • 生成器表达式获取的是一个生成器
    • 生成器表达式只是一个内存地址

    列表推导式

    • 列表推导式一目了然
    • 比较耗内存,所有数据一次性加载到内存
    • 得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器

    ​ 无论是生成器表达式,还是列表推导式,他只是Python给你提供了一个相对简单的构造方式,因为使用推导式非常简单,所以大多数都会为之着迷,这个一定要深重,推导式只能构建相对复杂的并且有规律的对象,对于没有什么规律,而且嵌套层数比较多(for循环超过三层)这样就不建议大家用推导式构建。

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

  • 相关阅读:
    字符串-06. IP地址转换
    字符串-05. 字符串循环左移
    字符串-04. 字符串逆序
    BZOJ 3110
    UOJ 34 fft板子
    BZOJ 2716
    BZOJ 2243
    BZOJ 3697
    BZOJ 1176
    BZOJ 2599
  • 原文地址:https://www.cnblogs.com/fanxss/p/11051492.html
Copyright © 2020-2023  润新知