• 推导式,集合推导式,生成器表达式及生成器函数day13


    1.推导式

    用一行循环判断遍历处一系列数据的方式

    推导式在使用时,只能用for循环和判断,而且判断只能是单项判断

    基本语法:

    lst = [i for i in range(1,51)]
    print(lst)
    

      

    普通推导式

    #[1,2,3,4]  => [2,8,24,64]
    lst = [1,2,3,4]
    #lst = [i*2**i for i in lst]
    lst = [i << i for i in lst]   #左移  相当于 i*2**i
    print(lst)
    

      

    带有条件判断的推导式

    lst = [1,2,3,4,5,6,67,7,8,]
    lst_new = []
    for i in lst:
        if i %2 == 0:
            lst_new.append(i)
    print(lst_new)
    
    #推导式改写
    lst = [i for i in lst if i % 2 == 0]
    print(lst)
    

      

    多循环推导式

    lst1 = ['王振','黄俊','刘伟']
    lst2 = ['魏小林','刘思敏','陈芮']
    lst_new = []
    for i in lst1:
        for j in lst2:
            res = i + '♥' + j
            lst_mwe.append(res)
    print(lst_new)
    
    
    #推导式改写
    lst = [i+'♥'+j for i in lst1 for j in lst2]
    print(lst)
    

      

    带有判断条件的多循环推导式

    lst_new = []
    for i in lst1:
        for j in lst2:
            if lst1.index(i) == lst2.index(j):
                res = i+'♥'+j
                lst_new.append(res)
    print(lst_new)
    
    
    #推导式改写
    lst = [i+'♥'+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
    print(lst)
    

      

    推导式练习:

    # ### 关于推导式的练习
    # (1).{'x': 'A', 'y': 'B', 'z': 'C' } 把字典写成x=A,y=B,z=C的列表推导式
    dic = {'x': 'A', 'y': 'B', 'z': 'C' }
    lst_new = []
    #常规
    for k,v in dic.items():
        res = k+'='+v
        lst_new.append(res)
    print(lst_new)
    
    lst = [k+'='+v for k,v in dic.items()]
    
    #(2) 把列表中所有字符变成小写  ["ADDD","dddDD","DDaa","sss"]
    #常规
    lst = ["ADDD","dddDD","DDaa","sss"]
    lst_new = []
    for i in lst:
        res = i.lower()
        lst_new.append(res)
    print(lst_new)
    
    lst = [i.lower() for i in lst]
    print(lst)
    
    #(3)x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中
    #方法一
    lst_new = []
    for x in range(6):
        for y in range(6):
            if x % 2 ==0 and y % 2 ==1:
                res = x,y
                lst_new.append(res)
    print(lst_new)
    #推导式
    lst = [(x,y) for x in range(6) for y in range(6) if x % 2==0 and y %2 ==1]
    print(lst)
    
    #方法二
    lst_new = []
    for x in range(6):
        if x % 2 == 0:
            for y in range(6):
                if y % 2 ==1:
                    res = x,y
                    lst_new.append(res)
    print(lst_new)
    
    
    #(4) 使用列表推导式,制作所有99乘法表中的运算
    for i in range(9,0,-1):
        for j in range(1,i+1):
            print('{:d}*{:d}={:2d}'.format(i,j,i*j),end='')
        print()
        
    #推导式
    lst = ['{:d}*{:d}={:2d}'.format(i,j,i*j) for i in range(9,0,-1) for j in range(i,i+1)]
    print(lst)
    
    # (5)#求M,N中矩阵和元素的乘积
    # M = [ [1,2,3], 
    #       [4,5,6], 
    #       [7,8,9]  ] 
    
    # N = [ [2,2,2], 
    #       [3,3,3], 
    #       [4,4,4]  ] 
    # =>实现效果1   [2, 4, 6, 12, 15, 18, 28, 32, 36]
    # =>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]
    M = [ [1,2,3] , [4,5,6] , [7,8,9]]
    N = [ [2,2,2] , [3,3,3] , [4,4,4]]
    '''
    M[0][0] * N[0][0] = 2
    M[0][1] * N[0][1] = 4
    M[0][2] * N[0][2] = 6
    
    M[1][0] * N[1][0] = 12
    M[1][1] * N[1][1] = 15
    M[1][2] * N[1][2] = 18
    
    M[2][0] * N[2][0] = 28
    M[2][1] * N[2][1] = 32
    M[2][2] * N[2][2] = 36
    #总结:能控制下标等于控制了最后的结果
    '''
    
    #第一个效果
    lst = [M[i][j]*N[i][j] for i in range(3) for j in range(3)]
    print(lst)
    '''第一层循环控制外层i=0的时候,j=0,1,2'''
    
    #第二个效果
    #[[],[],[]] 通过推导式遍历出三个新列表
    lst = [[] for i in range(3)]
    print(lst)
    '''
    外层i动的慢的,里层j动的快的,所有下标M[I][J]
    在拿出i的时候,里面的for循环了三遍 是在一个新的列表当中实现的
    '''                
    lst = [[M[i][j]*N[i][j] for j in range(3)] for i in range(3)]
    print(lst)
    

      

    2.集合推导式

    案例:

    '''
    案例:
        满足年龄在18到21,存款大于等于5000 小于等于5500的人。
        开卡格式为:尊贵VIP卡老X(姓氏),否则开卡格式为:抠脚大汉卡老X(姓氏)
    '''
    listvar = [
    	{"name":"王家辉","age":18,"money":10000},
    	{"name":"王水机","age":19,"money":5100},
    	{"name":"王鹏","age":20,"money":4800},
    	{"name":"李站","age":21,"money":2000},
    	{"name":"李小龙","age":180,"money":20}
    ]
    
    setvar = set()
    for i in listvar:
        if 18<= i['age'] <= 21 and 5000 <= i['money'] <=5500:
            res = '尊贵VIP卡老' + i['name'][0]
        else:
            res = '抠脚大汉卡者' + i['name'][0]
        setvar.add(res)
    print(setvar)
    
    #setvar = {三元运算符 + for i in iterable}
    setvar = {"尊贵VIP卡老" +  i["name"][0] if 18 <= i["age"] <= 21 and  5000 <= i["money"] <= 5500 else "抠脚大汉卡老" +  i["name"][0]   for i in listvar}
    

      

    3.字典推导式

    3.1 enumerate 函数

    enumerate(iterable,[start=0])
    功能:枚举,将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
    参数:
        iterable:可迭代行数据(常用迭代器,容器数据类型,可迭代对象range)
        start:可选择开始的索引号(默认从0开始索引)
    返回值:迭代器
    

      

    lst = ["吕洞宾","张果老","蓝采和","何仙姑","铁拐李","韩湘子","曹国舅","动感超人"]
    it = enumerate(lst,start=5)
    #可以设置开始是索引值 start = 5
    from collections import Iterator,Iterable
    res = isinstance(it,Iterable)
    print(res)
    
    #for + next 迭代所有数据
    for i in range(3):
        res = next(it)
        print(res)
    
    #list 强转迭代器
    res = list(it)
    print(res)
    
    #1.通过推导式配合enumerate 实现
    #(5,'吕洞宾')
    dic  = {k:v for k,v in enumerate(lst,start=1)}
    print(dic)
    

      

    3.2 zip函数

    zip(iterable,...,...)
    功能:将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中
    iterable:可迭代性数据(常用:迭代器,容器类数据类型,可迭代对象range)
    返回值:迭代器
    特点:不能配对的多余的值会被舍弃
    
    zip的基本使用
    lst1 = ["黄俊","朱佳怡","王振","魏小林"]
    lst2 = ["李博","刘伟","王颖倩"]
    lst3 = ["刘思敏","陈芮"]
    it = zip(lst1,lst2)
    # it = zip(lst1,lst2,lst3)
    print(isinstance(it,Iterator))
    
    #用list强转,瞬间拿到里面所有数据
    print(list(it))  #[('黄俊', '李博'), ('朱佳怡', '刘伟'), ('王振', '王颖倩')]
    
    #1.使用zip配合推导式实现
    dic = {k:v for k,v in zip(lst1,lst2)}
    print(dic)
    
    #通过dict 强转字典 实现
    dic = dict(zip(lst1,lst2))#{'黄俊': '李博', '朱佳怡': '刘伟', '王振': '王颖倩'}
    print(dic)
    

      

    4.生成器

    生成器本质是迭代器,允许自定义逻辑的迭代器
    迭代器和生成器区别:
        迭代器本身是系统内置的,重写不了,而生成器是用户自定义的,可以重写迭代逻辑
    生成器可以用两个方式创建:
        (1)生成器表达式(里面是推导式,外面用圆括号)
        (2)生成器函数(用def定义,里面含有yield)
    
    from collections import Iterator
    #生成器表达式,定义一个生成器用元组括号就是生成器
    gen = (i*2 for i in range(1,5))
    print(gen)
    
    print(isinstance(gen,Iterator))
    
    #next调用生成器
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    
    #2.for调用生成器
    gen = (i*2 for i in range(1,5))
    for i in gen:
        print(i)
        
    #3.for + next 调用生成器
    gen = (i*2 for i in range(1,5))
    for i in range(2):
        res = next(gen)
        print(res)
        
    #4.用list强转,瞬间拿到所有数据
    res = list(gen)
    print(res)
    

      

    5.生成器函数

    yield 类似于return
    共同点在于:执行到这句话都会把值返回出去
    不同点在于:yield每次返回时,会记住上次离开时执行的位置,下次再调用生成器,会从上一次执行的位置继续往下走下去,而return直接终止函数,每次重头调用
    yield 6 和 yield(6)  2种写法都可以 yield 6更推荐使用
    
    from collections import Iterator
    
    (1)基本语法
    def mygen():
        print('one')
        yield 1
        
        print('two')
        yield 2
        
        print('three')
        yield 3
    初始化生成器函数,返回生成器对象,简称生成器
    gen = mygen()
    print(isinstance(gen,Iterator))
    
    #第一次
    res = next(gen)
    print(res)
    #第二次
    res = next(gen)
    #第三次
    res = next(gen)
    print(res)
    
    解析:
     第一次调用,print('one') yield 1,记录当前代码执行的状态在多少行,直接把1返回,等待一下次调用 res = 1  print(1)
    第二次调用,从上一次代码的位置继续向下执行,print('two') yield 2,记录当前代码执行的状态在多少行,直接把2返回回去,等待下一次调用 res = 2 print(2)
    第三次调用,从上一次代码的位置继续向下执行,print('three') yield 3,记录当前代码执行的状态在多少行,把3直接返回,等待下一次调用 res = 3 print(3)
    如果在进行第四次调用,因为没有yield关键字返回数据,所以直接报错StopIteration
    
        
    

      

    send  可以发送数据,发送给上一个yield
    send 和 next的区别
    next只能取值
    send不但能取值,还能发送值
    send注意点:
        第一个send不能给yield传值,默认只能写None
        最后一个yield接收不到send的发送值
    def mygen():
        print('start')
        res = yield 111
        print(res)
        
        res = yield 222
    	print(res)
        
        res =yield 333
        print(res)
        
        print('end')
    #初始化生成器函数 -> 返回生成器对象 ->简称生成器
    gen = mygen()
    #第一次调用
    #第一次只能默认发送None,因为第一次没有上一个yield
    val = gen.send(None)
    print(val)
    
    #第二次调用
    val = gen.send(444)
    print(val)
    
    #第三次调用
    val = gen.send(555)
    print(val)
    #555
    #333
    
    #第四次调用error
    #val = gen.send(666)
    #print(val)
    
    解析:
    无论是next还是send都可以调用生成器里面的数据,send不但可以调用,还可以给yield发送值
    第一次调用send,只能发送None,因为还没有遇到yield,代码从上到下执行,print('start') 遇到res = yield 111 记录当前代码执行的状态在多少行,把111值返回,等待一下调用外面的val=111 print(111)
    第二次代用send,把444发送给上一次保存的位置行,yield进行接收res=444行往下执行,print(444) 遇到res = yield 222记录当前代码执行的状态在多少行,把222值返回,等待下一次调用,外面的val=222 print(222)
    第三次调用send,把555发送给上一次保存的位置行,yield进行接收res = 555,再往下执行,print(555),遇到res = yield 333,外面的val = 333,print(333)
    第四次调用send,把666发送给上一次保存的位置行,yield进行接收res = 666,再往下执行,print(666),print('end') 没有任何yield返回数据,出现StopIteration到此程序彻底结束、
    

      

    yield from  将一个可迭代对象变成一个迭代器返回
    def mygen():
        lst = ["魏小林","陈宁波","朱胜"]
        yield from lst
    gen = mygen()
    print(next(gen))
    print(next(gen))
    print(next(gen))
    
    
    案例:用生成器来写一个斐波那契数列
    生成器应用在大数据的场景中,按照需求依次取值,切记不要直接迭代生成器所有数据
    一旦数据量较大,类似于死循环
    #0 1  1  2  3 5 8 13 21 34 55 ..... 
    def mygen(maxlength):
        a = 0
        b =1
        i = 0
        while i <maxlength:
            yield b
            #当前值 = 上上个值 + 上一个值
            a , b  = b ,a+b
            i += 1
    gen = mygen(50)
    for i in range(30):
        print(next(gen))
    

      

  • 相关阅读:
    spock2.x结合mockito静态mock
    线程池的拒绝策略及常见线程池
    正确关闭线程池
    对线面试官 | 字节跳动一面
    记一次oom问题排查
    MySQL索引下推,原来这么简单!
    vs2019 编译 protocol buffers
    每日一库:classList.js
    每日一库:tinycon.js
    算法: 有效的括号
  • 原文地址:https://www.cnblogs.com/weiweivip666/p/12910271.html
Copyright © 2020-2023  润新知