• 13 生成器函数 生成器表达式 列表推导式 字典推导式 集合推导式 元祖没有推导式


    主要内容:

    1. 生成器:生成器的实质就是迭代器,在python中有三种方式可以获取生成器:

      通过生成器函数

      通过各种推导式来实现生成器

      通过数据的转换也可以实现生成器

    2. 生成器函数

      a: 函数中包含了yield的就是生成器函数.

       注意:生成器函数被执行,获取的是生成器,而不是函数的执行

    def fn():
        print("张杰")
        yield "谢娜"    #函数中包含yeild说明该函数不是一个普通的函数,而是生成器函数
        print("你好啊")
        yield "hi"
        print("明日之子")
        yield 'pick田四火'
    s = fn()       #创建一个生成器
    print(s.__next__())
    print(s.__next__())
    print(s.__next__())      #最后一个yield执行完毕,在执行yield会报错.
    #return 直接返回函数结果,结束调用
    #yeild  返回结果,可以让函数分段进行
    

      b: 注意

    def func():
        print("张杰")
        yield "谢娜"    #函数中包含yeild说明该函数不是一个普通的函数,而是生成器函数
        print("明日之子")
        yield 'pick田四火'
    g1 = func()                  #表示两个相同的生成器,第一个从头开始指向下一个元素,第二个也是从头开始指向元素.
    g2 = func()
    print(g1.__next__())        #张杰谢娜
    print(g1.__next__())        #明日之子,田四火
    print("==============")
    print(g2.__next__())        #张杰谢娜
    

      c: 生成器的优点,可以节约内存,

      例题:例如老男孩教育要给每个培训的学员定制一套衣服,共10000套.

    def fn():
        lst = []
        for i in range(1,10001):
            lst.append('衣服%s' % i)
        return lst
    s = fn()
    print(s)
    

      缺点:一次性全部拿出来,会很占用内存.

    def fn():
        lst = []
        i = 1
        while i < 100001:
            yield '衣服%s' % i
            i = i + 1
    g = fn()
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    

      使用生成器.一次就一个,用多少生成多少,生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就指到哪.下一次继续或许指针指向的值

      d: 拿到的是生成器. 生成器的本质是迭代器. 迭代器可以被迭代 生成器可以直接for循环

    def func():
        yield 11
        yield 22
        yield 33
    g = func()    #拿到的是生成器,生成器的本质是迭代器,迭代器可以被迭代,生成器可以直接for循环
    for i in g:
        print(i)
    

      e: list[g]

    def func():
        yield 11
        yield 12
        yield 13
        yield 14
    g = func()           #获取生成器
    lst = list(g)        #括号里必须为可迭代对象
    print(lst)

    3. send: send和__next__一样,都可以让生成器执行到下一个yield.

      send和__next__的区别:

        send():也可以让生成器向下执行一次,给上一个yield传一个值,第一个不能用send,最后一个也不要传值.

        __next__:可以使生成器向下执行一次.

    def eat():
        print("我吃什么啊")
        a =  yield  "馒头"
        print("a=",a)
        b =  yield  "大饼"
        print("b=",b)
        c =  yield  "韭菜盒子"
        print("c=",c)
        yield  "GAME OVER"
    gen = eat()      # 获取⽣成器
    print(gen. __next__ ())      #到yield结束,返回馒头
    print(gen.send("胡辣汤"))    #可以给上一个yield传值,a = 胡辣汤
    print(gen.send("狗粮"))      #可以给上一个yield传值,b = 狗粮
    print(gen.send("猫粮"))      #可以给上一个yield传值,c = 猫粮
    

    4. 列表推导式

    语法:[最终结果 for     变量   in  可迭代对象  ]

    语法:[最终结果  for   变量   in  可迭代对象  if 条件]

      生成列表,里面装1-14数据

        普通模式

    li = []
    for i in range(1,15):
        li.append('python%s期' % i)
    print(li)
    

        采用推导式

    li = ['python%s期' % i for i  in range(1,15)]
    print(li)
    # ['python1期', 'python2期', 'python3期', 'python4期', 'python5期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期', 'python11期', 'python12期', 'python13期', 'python14期']
    

      获取100以内能被3整除的数的平方

    li = [i*i for i in range(101) if i % 3 == 0 ]
    print(li)
    

      寻找名字中带有两个e的人的名字

    names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,
    'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']]
    lst = [name for first in names for name in first if name.count("e") == 2]
    print(lst)
    

    5. 字典推导式

      dic = {"a":"b", "c":"d"},把字典中的key和value互换:

    dic = {'a':'b','c':'d'}
    new_dic = { dic[key]:key for key in dic}
    print(new_dic)
    

      lst1作为key,lst2作为value

    lst1 = ["alex", "wusir", "taibai", "ritian"]
    lst2 = ['sb', "很色", "很白", "很牛"]
    dic = {lst1[i]:lst2[i] for i in range(len(lst1))}      #取他们的索引
    print(dic)
    

    6. 集合推导式

    lst = ['马化腾','马化腾','王建中','张建忠','张雪峰','张雪峰']
    s = {i for i in lst}
    print(s)
    

    7. 生成器表达式

      把列表推导式[]变成(),就成为生成器表达式

      格式(最终结果  for 变量 in 可迭代对象)

    gen = ("麻花藤我第%s次爱你" % i for i in range(10))
    print(gen)                #<generator object <genexpr> at 0x0000021314580F68>
    

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

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

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

    gen = (i for i in range(100) if i % 3 == 0)
    for e in gen:
        print(e)
    

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

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

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

         形象的说明:列表推导式:直接拿到一筐子鸡蛋,生成器表达式:拿到一个老母鸡,需要的时候母鸡就给你下鸡蛋.

      生成器的惰性机制:

        生成器只有在访问的时候才取值,说白了,你找他要,他才给你,不找他要,他不会执行.

    # 生成器的惰性机制:
    def func():
        print(111)
        yield 222
    g = func()             #通过生成器函数获得的生成器
    g1 = (i for i in g)   #通过生成器表达式获得的生成器g1
    g2 = (i for i in g1)  #生成器g2
    print(list(g))     #获取g中的数据,这是func()才会执行,打印111,获取到222,g完毕.
    print(list(g1))    #获取g1中的数据,g1 的数据来源g,但是g已经取完了,g1也就没有数据了.
    print(list(g2))
    

      有关生成器表达式的惰性机制的一道面试题

    def add(a, b):
        return a + b
    def gen():
        for r_i in range(4):
             yield r_i
    g = gen()
    for n in [2, 10]:
        g = (add(n, i) for i in g)  #生成器的惰性机制,生成器只有在访问的时候才取值,说白了,你找他要,他才给你值.不找他要不会给你的
    print(list(g))                   #不到最后不会拿值:惰性机制.
    

      

    def add(a, b):
        return a + b
    def test():
        for r_i in range(4):
             yield r_i
    # g = test()
        # g = (add(n, i) for i in g)  #生成器的惰性机制,生成器只有在访问的时候才取值,说白了,你找他要,他才给你值.不找他要不会给你的
        g = (add(10, i) for i in (add(10, i) for i in 0,1,2,3)  #第二次执行的时候替换后面的g
        g = (add(10, i) for i in 10,11,12,13
    print(list(g))
    # lst(g) = [20,21,22,23]
    

      

      

      

  • 相关阅读:
    理解C#中的 async await
    kube-proxy IPVS 模式的工作原理
    Kilo 使用教程
    Wireguard 全互联模式(full mesh)配置指南
    我为什么不鼓吹 WireGuard
    iTerm2 实现 ssh 自动登录,并使用 Zmodem 实现快速传输文件
    在 Docker Desktop 中启用 K8s 服务
    ABP 适用性改造
    ABP 适用性改造
    在 ASP.NET Core 应用中使用 Cookie 进行身份认证
  • 原文地址:https://www.cnblogs.com/gyh412724/p/9328799.html
Copyright © 2020-2023  润新知