Python 函数 IV (生成器等)

1.今日内容

  1. 生成器初识
  2. 生成器产生方式
  3. yield与return的区别
  4. yield与yield from的区别
  5. send与next的区别
  6. 列表推导式,生成器表达式(字典推导式,集合推导式)
  7. 闭包

2.具体内容

  1. 生成器初识

    • 生成器本质就是迭代器,python社区中生成器与迭代器是一种概念。生成器与迭代器的唯一区别:迭代器都是python给你提供的已经写好的工具或者通过数据转化得来的,(比如文件句柄,iter([1,2,3]))。生成器是我们自己用python代码构建的工具
  2. 生成器产生方式

    • 生成器函数
    def func():
      print(666)
      yield 2,4,6
      print(888)
      yield 8
    ret = func() #生成器对象
    print(ret) # <generator object func at 0x0000000001E10F68>
    print(next(ret))
    print(next(ret))
    #只要函数中出现yield,那么他就不是函数,它是生成器函数
    #一个next对应一个yield,next超过yield数量会报错,StopIteration
    
    • 生成器表达式
    ret = (i for i in range(3))
    print(ret) #<generator object <genexpr> at 0x10307f0d0>
    #如何触发生成器(迭代器)取值
    #1.next(obj)
    print(next(ret))
    #2.for 循环
    for i in range(3):
      print(next(ret))
    #3.数据转化
    print(list(obj))#[0,1,2]
    
    • python给你提供的一些内置函数,返回一个生成器
    l1 = [1,2,3]
    ret = iter(l1)
    print(next(ret))
    
  3. yield与与return的区别

    • return:结束函数,给函数的执行者返回值(多个值通过元组的形式返回)
    • yield:不结束函数,对应着给next返回值(多个值通过元组的形式返回)
  4. yield 与yield from

    #yield from 的作用
    def func():
      yield from [1,2,3]
    ret = func()
    print(next(ret))#1
    print(next(ret))#2
    print(next(ret))#3
    #yield:对应yield给next返回值
    #yield from:将一个可迭代对象的每一个元素返回给next
    #yield from:节省代码,提升效率(代替for循环)
    
  5. send与next区别

    • 相同点
      • send和next都可以让生成器对应的yield向下执行一次
      • 都可以获取yield生成的值
    • 不同点
      • 第一次获取yield值只能用next,不能用send(可以send(None))
      • send可以给上一个yield传递值
    def func(name):
      print(f'{name} ready to eat')
      while 1:
        food = yield '骨头'
        print(f'{name} start to eat {food}')
    dog = func('将军')
    next(dog)
    #第一次必须用next让指针停留在第一个yield后面不能用shed(send(None))
    #如
    ret = dog.send(None)
    #与next一样,可以获取yield的值
    #还可以给上一个yield发送值
    ret = dog.send('香肠')
    print(ret)
    
  6. 列表推导式,生成器表达式(字典推导式,集合推导式)

    • 列表推导式:一行代码构建一个有规律比较复杂的列表
    #
    l1 = []
    for i in range(5):
      l1.append(i)
    print(l1)
    #列表推导式
    l1 = [i for i in range(1,11)]
    print(l1)
    
    • 两种构建方式

      • 循环模式:[变量(加工后的变量) for 变量 in iterable]
      # 将10以内所有整数的平方写入列表。
      print([i**2 for i in range(1,11)])
      # 100以内所有的偶数写入列表.
      print([i for i in range(2,101,2)])
      # 从包子1期到包子100期写入列表list
      print([f'包子{i}期' for i in range(1,101)])
      
      • 筛选模式:[变量(加工后变量) for 变量 in iterable if 条件]
      # 1-100里大于49的数
      print([i for i in range(1,101) if i > 49])
      # 三十以内可以被三整除的数
      print([i for i in range(1,31) if i %3 == 0])
      # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
      l1 = ['barry', 'fdsaf', 'alex', 'sb', 'ab']
      print([i.upper() for i in l1 if len(i) > 3])
      # 找到嵌套列表中名字含有两个‘e’的所有名字
      names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
      print(s for i in names for s in i if s.count('e') == 2)
      
    • 列表推导式的优缺点

      简单,快捷;但可读性不高,不好排错

    • 字典推导式,集合推导式

    # 字典推导式,集合推导式:  两种模式: 循环模式,筛选模式
    l1 = ['小潘', '怼怼哥','西门大官人', '小泽ml亚']
    # {0: '小潘', 1: '怼怼哥', 2: '西门大官人'}
    #字典推导式
    print({i:l1[i] for i in range(len(l1))})
    #集合推导式
    print({i for i in range(10)})
    
  7. 闭包

    • 什么是闭包
      • 闭包只能存在嵌套函数中
      • 内层函数对外层函数非全局变量的引用(使用),就会形成闭包
      • 被引用的非全局变量也称自由变量,这个自由变量会与内层函数产生一个绑定关系
      • 自由变量不会在内存中消失
    • 闭包的作用
      • 保证数据的安全
    def func():
      l1  = []
      def inner(s):
        l1.append(s)
        total = sum(l1)
        return total/len(l1)
      return inner
    s = func()
    print(s(100))
    print(s(120))
    print(s(140))
    
    #坑
    def func(a,b):
      def inner():
        print(a)
        print(b)
      return inner
    a = 2
    b = 3
    ret = func(a,b)
    
    #如何判断是闭包
    print(ret.__code__.co_freevars)
    
原文地址:https://www.cnblogs.com/xiaohei-chen/p/11940880.html