zoukankan      html  css  js  c++  java
  • Day-12 生成器

    一、生成器

      生成器实质就是迭代器

      两种方式写生成器:

        1.生成器函数

        2.生成器表达式

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

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

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

    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

      生成器函数有什么用

      普通的程序会占用内存

    def buy():
        lst = []
        for i in range(10000):
             lst.append("衣服%s" % i)
        return lst
    
    lst = buy()
    print(lst)

      利用生成器,需要一件拿一件节省内存空间

    def cloth():
        for i in range(10000):
            yield "衣服"+str(i)
    cl = cloth()
    print(cl.__next__)
    print(cl.__next__)
    print(cl.__next__)
    print(cl.__next__)

      区别:第一种是直接一次性全部拿出来,会和占用内存,第二种使用生成器,一次就一个,用多少拿多少,生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就知道哪儿,下一次继续获取指针指向的值。

      特性:和迭代器一样

        1.节省内存

        2.惰性机制

        3.只能往前

      生成器还可以使用__next__(), send()来访问生成器

      send()可以给上一个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

    二、列表推导式以及其他推导式

      先看这样的代码

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

      替换成列表推导式:

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

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

      列表推导式的常用写法:[结果 for 变量 in 可迭代对象]

      我们也可以对列表中的数据进行筛选

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

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

      字典推导式和集合推导式:[结果 for 变量 in 可迭代对象 if 条件]

    s = {i*"胡辣汤" for i in range(10)}  #集合推导式
    print(s)
    
    dic = {"张无忌":"赵敏", "杨过":"小龙女", "郭靖":"黄蓉"}
    # 把字典中的key和value互换
    # dic = {"赵敏":"张无忌", "小龙女":"杨过", "黄蓉":"郭靖"}
    dic1 = { v:k for k, v in dic.items()}  # 强化  #字典推导式
    print(dic1)

      没有元组推导式,因为元组没有增删改操作

    三、生成器表达式

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

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

      打印的结果就是一个生成器,我们可以使用for循环来循环这个生成器:

    gen = ("麻花藤我第%s次爱你" % i for i in range(10))
    for i in gen:
        print(i)

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

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

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

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

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

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

    def func():
        print(111)
        yield 222
    g = func() # 生成器g
    g1 = (i for i in g) # 生成器g1. 但是g1的数据来源于g
    g2 = (i for i in g1) # 生成器g2. 来源g1
    print(list(g)) # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕
    print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据了
    print(list(g2)) # 和g1同理

      在Python3中提供了一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回

    def gen():
        lst = ["麻花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
        yield from lst
    
    g = gen()
    for el in g:
    print(el)

      小坑: yield from是将列表中的每一个元素返回. 所以. 如果写两个yield from 并不会产生交替
    的效果.

    def gen():
        lst = ["麻花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
        lst2 = ["饼铛还是微星的好", "联想不能煮鸡蛋", "微星就可以", "还可以烙饼"]
        yield from lst
        yield from lst2
    
    g = gen()
    for el in g:
        print(el)
    
    效果:
    
    麻花藤
    胡辣汤
    微星牌饼铛
    Mac牌锅铲
    饼铛还是微星的好
    联想不能煮鸡蛋
    微星就可以
    还可以烙饼

     总结:推导式有,列表推导式,字典推导式,集合推导式,没有元组推导式

  • 相关阅读:
    让flask在出现语法错误时仍然自动重启
    ubuntu配置zsh和oh-my-zsh
    docker运行python3.6+flask小记
    vscode python3 配置生成任务
    从flask视角理解angular(四)Route
    从flask视角理解angular(三)ORM VS Service
    从flask视角理解angular(二)Blueprint VS Component
    从flask视角学习angular(一)整体对比
    Linux高级变量
    linux系统中查看日志及系统信息
  • 原文地址:https://www.cnblogs.com/minusone/p/9892471.html
Copyright © 2011-2022 走看看