美文网首页
15. Python之yield表达式和生成式

15. Python之yield表达式和生成式

作者: 随便写写咯 | 来源:发表于2021-02-01 14:17 被阅读0次

    1 yield表达式的应用

    1.1 利用yield返回值给函数体的变量传值

    def func(name):
        print('%s 准备点菜' %(name))
        while True:
                dish = yield None
                print('%s 点了 %s' %(name, dish))
    
    g=func('第一桌')
    first_dish = next(g)
    print(first_dish)
    
    第一桌 准备点菜
    None  # 利用yield传值, 需要指定yield的返回值
    
    def func(name):
        print('%s 准备点菜' %(name))
        while True:
                 dish = yield '鲍鱼'
                 print('%s 点了 %s' %(name, dish))
    
    g=func('第一桌')
    first_dish = next(g)
    print(first_dish)
    
    第一桌 准备点菜
    鲍鱼
    

    1.2 yield表达式格式生成器

    g.send() 给yield赋值, yield会将值转给变量, 此时变量拿到的是yield从g.send()接收到的值
    g.send() 相当于执行了next方法, 只不过具备了传值功能, 如果单纯的执行next方法, 那么给变量传的就是yield的返回值
    
    def func(name):
        print('%s 准备点菜' %(name))
        while True:
            dish = yield
            print('%s 点了 %s' %(name, dish))
    
    g=func('第一桌')
    
    g.send(None) # 第一次执行g.send需要传None来初始化生成器, 让函数先挂起在yield,等待send传值
    g.send('土豆') # 之后每一次变量dish的值, 取决于通过g.send()给yield传的值, 每执行一次send, 会把值传给变量, 然后打印print, 之后再回到yield, 等着下一次send传值
    g.send('地瓜') # 第二次传了土豆, 那么yield就会把土豆传给dish, 之后在打印print
    
    第一桌 准备点菜
    第一桌 点了 土豆
    第一桌 点了 地瓜
    

    通过g.close()结束传值

    def func(name):
        print('%s 准备点菜' %(name))
        while True:
            dish = yield
            print('%s 点了 %s' %(name, dish))
    
    g=func('第一桌')
    
    g.send(None)
    g.send('土豆')
    g.send('地瓜')
    g.close()
    g.send('肉')
    
        g.send('肉')
    StopIteration
    第一桌 准备点菜
    第一桌 点了 土豆
    第一桌 点了 地瓜
    

    g.send()方法, 一次只能传一个值, 但是可以传容器类型

    1.3 表达式综合应用

    def func(name):
        print('%s 准备点菜' %(name))
        while True:
            dish = yield 111
            print('%s 点了 %s' %(name, dish))
    
    g=func('第一桌') # 运行函数, 拿到生成器
    
    res1 = g.send(None)  # 首次执行, 需要通过send(None)来初始化生成器, 让函数挂起在yield,等待传值, 之后每次通过send给yield传值, 进而给变量dish传值, 每次传值yield的返回值就是yield后的值
    print(res1)
    res2 = g.send('土豆')
    print(res2)
    res3 = g.send('地瓜')
    print(res3)
    
    第一桌 准备点菜
    111
    第一桌 点了 土豆
    111
    第一桌 点了 地瓜
    111
    

    执行顺序

    1. 执行send方法,将参数传给yield, 进而传给dish变量
    2. 执行print, 函数代码结束, 返回while循环, 然后将yield后的值返回
    3. yield的返回值就看yield后跟了什么, yield拿到返回值后, 程序挂起在yield, 等待下一次send传值
    

    yield返回值是列表的情况

    def func(name):
        print('%s 准备点菜' %(name))
        food_list = []
        while True:
            dish = yield food_list
            print('%s 点了 %s' %(name, dish))
            food_list.append(dish)
    
    g=func('第一桌')
    
    1. 第一步, 执行send(None), 初始化生成器, yield返回空列表,程序挂起在yield等待send传值
    res1 = g.send(None)
    print(res1) # g.send()的返回值就是yield后的值
    
    第一桌 准备点菜
    []
    
    1. 第二次, send传值'土豆'
    1. yield从send拿到土豆, 然后传给dish, 接着执行print代码
    2. print代码执行完, 执行列表追加, 将土豆追加到列表, 此时代码执行完, 返回循环, 进入yield
    3. yield拿到返回值food_list列表, 因此打印res2, 会拿到yield的新的返回值也就是追加后的列表
    4. 程序挂起在yield, 等待下次send传值
    
    def func(name):
        print('%s 准备点菜' %(name))
        food_list = []
        while True:
            dish = yield food_list
            print('%s 点了 %s' %(name, dish))
            food_list.append(dish)
    
    g=func('第一桌')
    
    res1 = g.send(None)
    print(res1)
    res2 = g.send('土豆')  #
    print(res2)
    
    1. 第三次, send传值'地瓜'
    def func(name):
        print('%s 准备点菜' %(name))
        food_list = []
        while True:
            dish = yield food_list
            print('%s 点了 %s' %(name, dish))
            food_list.append(dish)
    
    g=func('第一桌')
    
    res1 = g.send(None)
    print(res1)
    res2 = g.send('土豆')
    print(res2)
    res3 = g.send('地瓜')
    print(res3)
    
    第一桌 准备点菜
    []
    第一桌 点了 土豆
    ['土豆']
    第一桌 点了 地瓜
    ['土豆', '地瓜']
    

    2 三元表达式

    可以简化利用条件判断拿到返回值的需求
    
    格式:
    
    条件成立的返回值 if 条件判断 else 条件不成立的返回值
    

    正常情况根据条件拿到返回值

    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    res = max2(1,2)
    print(res)
    
    2
    

    利用三元表达式

    x = 1
    y = 2
    res = 111 if x > y else 222
    print(res)
    
    222
    

    函数内使用三元表达式

    def max2(x,y):
        res = 111 if x > y else 222
        print(res)
    max2(1,2)
    
    2
    

    3 列表生成式

    用精简的代码生成新的列表
    

    举例: 将名字中以soccer结尾的元素提取到新的列表

    play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
    
    soccer_play = []
    for name in play:
        if name.endswith('soccer'):
            soccer_play.append(name)
    print(soccer_play)
    
    ['david_soccer', 'owen_soccer', 'cluo_soccer']
    

    利用列表生成式

    play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
    
    soccer_play = [name for name in play if name.endswith('soccer')]
    print(soccer_play)
    

    列表生成式格式

    新列表 = [如果条件成立就追加到列表的值 for 循环 if 条件判断]
    新列表 = [如果条件成立就追加到列表的值 for 循环] # 可以不接if条件, 那默认就是条件永远为True
    新列表 = [任何值 for 循环] # 追加的值可以是任意值
    

    案例: 把列表中所有小写字母, 变成大写字母

    play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
    
    new_play = [name.upper() for name in play]
    print(new_play)
    
    ['DAVID_SOCCER', 'OWEN_SOCCER', 'CLUO_SOCCER', 'MICHAEL_BASKETBALL']
    

    案例: 把列表中所有名字去掉_soccer后缀

    play = ['david_soccer','owen_soccer','cluo_soccer','michael_basketball']
    
    new_play = [name.replace('_soccer','') for name in play]
    
    print(new_play)
    
    ['david', 'owen', 'cluo', 'michael_basketball']
    

    4 字典生成式

    案例1:

    keys = ['name','age','job']
    dict = {key:None for key in keys}
    print(dict)
    
    {'name': None, 'age': None, 'job': None}
    

    案例2:

    items = [('name','admin'),('age','20'),('gender','male')]
    dict = {k:v for k,v in items if k != 'gender'} # 利用元组的解压赋值, 判断k是否不等于gender, 如果成立就加入到字典
    print(dict)
    

    5 集合生成式

    案例:

    keys = ['name','age','gender']
    set = {key for key in keys}
    print(set)
    

    6 生成器表达式

    综合案例: 统计一个文本中的字符总个数

    方法1: 代码过长

    with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
        sum = 0  # 初始化总个数为0
        for i in f: # for循环一个文件, 每次取出文件的一行, 并且是字符
            sum += len(i) # len(i)计算出每行的字符个数, 追加给sum
        print(sum)
    

    方法2: 虽然代码精简, 但是一旦文件行数过多的情况下, 每次统计出来一行的字符个数, 再追加到列表, 会造成列表元素过多, 占用内存过大

    with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
        list = [len(i) for i in f ]
        print(sum(list))
    
    方法3: 利用生成器表达式, 效率最高
    with open(r'user_info.txt', mode = 'rt', encoding='utf-8') as f:
        res = sum((len(line) for line in f))
        print(res)
    

    相关文章

      网友评论

          本文标题:15. Python之yield表达式和生成式

          本文链接:https://www.haomeiwen.com/subject/pktdtltx.html