• Python生成器/生成器函数/推导式/推导式函数


    1. 生成器
      生成器的本质就是迭代器

      在python中有三种⽅方式来获取⽣生成器:

        1. 通过生成器函数
        2. 通过各种推导式来实现⽣成器
        3. 通过数据的转换也可以获取生成器

      生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), send(): 给上一个yield传值).
      生成器一般由生成器函数或者生成器表达式来创建
      其实就是手写的迭代器

    2. 生成器函数
      和普通函数没有区别. 里面有yield的函数就是生成器函数.
      生成器函数在执行的时候. 默认不会执行函数体. 返回生成器
      通过生成器的__next__()分段执行这个函数.
      send() 给上一个yield传值, 不能再开头(没有上一个yield), 最后一个yield也不可以用send()

    ⾸先, 我们先看一个很简单的函数:

    def func():
        print("111")
        return 222
    ret = func()
    print(ret)
    结果: 111 222

     

    将函数中的return换成yield就是生成器

    def func():
        print("111")
        yield 222
    ret = func()
    print(ret)
    结果:
    <generator object func at 0x10567ff68>

      运⾏的结果和上⾯不一样. 为什么呢. 由于函数中存在了yield. 那么这个函数就是⼀个生成器 函数. 这个时候. 我们再执行这个函数的时候. 就不再是函数的执行了. ⽽是获取这个生成器. 如何使用呢? 想迭代器. 生成器的本质是迭代器. 所以. 我们可以直接执⾏__next__()来执行

    以下生成器:

    def func():
        print("111")
    yield 222
    gener = func() # 这个时候函数不会执行. ⽽是获取到生成器
    ret = gener.__next__() # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据
    print(ret)
    结果:
    111
    222

    那么我们可以看到, yield和return的效果是一样的. 有什么区别呢? yield是分段来执⾏行一个函数. return呢? 直接停止执⾏函数.

    def func():
        print("111")
        yield 222
        print("333")
        yield 444
    gener = func()
    ret = gener.__next__()
    print(ret)
    ret2 = gener.__next__()
    print(ret2)
    ret3 = gener.__next__() # 最后⼀个yield执⾏完毕. 再次__next__()程序报错, 也就是说. 和return⽆关了.
    print(ret3)
    结果:
    111
    Traceback (most recent call last): 222
    333
      File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in
    <module>
    444
    ret3 = gener.__next__() # 最后一个yield执行完毕. 再次__next__()程序报错, 也就是说. 和return⽆关了.
    StopIteration

    当程序运⾏完最后一个yield. 那么后⾯继续进行__next__()程序会报错.

    我们来看send⽅方法, send和__next__()⼀一样都可以让⽣生成器执⾏行行到下⼀一个yield.

    def eat(): 
        print("我喜欢玩王者荣耀的:") 
        a = yield "鲁班" 
        print("a=",a)
        b = yield "程咬金" 
        print("b=",b)
        c = yield "安琪拉" 
        print("c=",c) 
        yield "GAME OVER"
    
    gen = eat() # 获取⽣成器
    ret1 = gen.__next__() 
    print(ret1)
    ret2 = gen.send("大乔") 
    print(ret2)
    ret3 = gen.send("后裔) 
    print(ret3)
    ret4 = gen.send("马克") 
    print(ret4)

    send和__next__()区别:

    1. send和next()都是让⽣成器向下走一次
    2. send可以给上一个yield的位置传递值,不能给最后一个yield发送值.在第一次执⾏⽣成器代码的时候不能使用send()

    ⽣成器可以使⽤for循环来循环获取内部的元素:

    def func():
        print(111)
        yield 222
        print(333)
        yield 444
        print(555)
        yield 666
    gen = func()
    for i in gen:
      print(i)
    结果: 111 222 333 444 555 666

    3. 推导式
      1. 列表推导式 [结果 for循环 条件筛选]

    首先我们先看一下这样的代码, 给出一个列列表, 通过循环, 向列表中添加1-14 :

    lst = []
    for i in range(1, 15):
        lst.append(i)
    print(lst)

    替换成列列表推导式:

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

    列表推导式是通过⼀行来构建你要的列表, 列表推导式看起来代码简单. 但是出现错误之后很难排查.

    筛选模式:
      [ 结果 for 变量量 in 可迭代对象 if 条件 ]

    # 获取1-100内所有的偶数
    lst = [i for i in range(1, 100) if i % 2 == 0] 
    print(lst)

    ⽣成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()

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

    ⽣成器表达式也可以进行筛选:

    # 获取1-100内能被3整除的数
    gen = (i for i in range(1,100) if i % 3 == 0) 
    for num in gen:
        print(num)

      2. 字典推导式 {k:v for循环 条件筛选}

    # [11,22,33,44] => {0:11,1:22,2:33,3:44}
    lst = [11,22,33,44]
    dic = {i:lst[i] for i in range(len(lst)) if i < 2}
        print(dic)
    # 语法:{k:v for循环 条件筛选}

      3. 集合推导式 {k for循环 条件}

    # 集合推到式
    lst = [1,1,4,6,7,7,4,2,2]
    s = {el for el in lst}
    print(s)
    s = set(lst)
    print(s)

    4. 生成器表达式

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

      1. 列表推导式比较耗内存.一次性加载.生成器表达式几乎不占⽤内存.使⽤的时候才分配和使⽤内存

      2. 得到的值不⼀样.列表推导式得到的是一个列列表.⽣成器表达式获取的是一个生成器.

      (结果 for循环 条件)
      特点:
        1. 惰性机制
        2. 只能向前
        3. 节省内存

  • 相关阅读:
    <li>标签在ie6下的上下间隔的BUG解决办法
    win7 瘦身 减肥 记录!
    学习系统封装半年经验总结!
    DIV 类似 hover 悬停效果 鼠标移动上去变化
    解决 WIN7 部署 安装驱动包时出现的驱动签名提示 办法!
    Windows 7 瘦身大全 系统减肥 轻松 瘦身 减肥 3个G
    JS 判断 取 当前系统类型 可用来定义某些WIN7系统和XP系统下字体区别
    JS 判断 当前浏览器类型
    EasyBoot常用的命令
    Win7封装保持任务栏锁定项不变的解决方法
  • 原文地址:https://www.cnblogs.com/shagudi/p/10962976.html
Copyright © 2020-2023  润新知