zoukankan      html  css  js  c++  java
  • python学习9-生成器(转载)

    什么是生成器?

    生成器的实质就是迭代器,我们能够从生成器中一个一的拿值

    python中获取生成器的方式有三种:

    1、通过生成器函数

    2、通过生成器表达式

    3、通过数据转换也可以获取生成器(某些对象执行一个方法就能返回一个生成器,这个现在用不到)

    一、 生成器函数

    1 def gen():
    2     代码块
    3     yield 返回值
    4 
    5 gen() #表示获取一个生成器,是一个内存地址,装的是代码,并不执行,用的时候才会执行

    将return换成yield就是生成器函数了,上面就是生成器函数的格式。yield的作用是代码执行到这里就会停止,并且会返回一个值,所以代码能够分段执行,这就是生成器能逐个拿值的原因。

    对于生成器函数,函数名+()并不表示函数执行,而是获取一个生成器对象。生成器装的是代码,只有在需要拿值的时候才会执行,这是生成器的惰性机制。

    1、通过__next__访问生成器

    # def gen():
    # print("娃哈哈")
    # yield '爽歪歪'
    # print("酸酸乳")
    # yield 'AD钙奶'
    # print('黄焖鸡米饭')
    #
    # ret = gen() #获取生成器对象,生成器装的是代码,要的时候运行一段
    # print(ret) #<generator object gen at 0x0000000001E12F10> 生成器 generator
    # print(ret.__next__()) #调用__next__才会执行,返回爽歪歪
    # print(ret.__next__()) #调用__next__才会执行,返回Ad钙奶
    #print(ret.__next__()) #StopIteration 迭代器,就找yield,找不到就会报错 往下运行,打印出了“黄焖鸡米饭”,但是找不到yield,所以报错

    __next__()

    复制代码
     1 # def gen():
     2 #     print("娃哈哈")
     3 #     yield '爽歪歪'
     4 #     print("酸酸乳")
     5 #     yield 'AD钙奶'
     6 #     print('黄焖鸡米饭')
     7 #
     8 # ret = gen()  #获取生成器对象,生成器装的是代码,要的时候运行一段
     9 # print(ret)   #<generator object gen at 0x0000000001E12F10>    生成器  generator
    10 # print(ret.__next__())   #调用__next__才会执行,返回爽歪歪
    11 # print(ret.__next__())    #调用__next__才会执行,返回Ad钙奶
    12 #print(ret.__next__())   #StopIteration     迭代器,就找yield,找不到就会报错  往下运行,打印出了“黄焖鸡米饭”,但是找不到yield,所以报错
    复制代码

    2、通过send()访问生成器

    send()可以取值的同时给上一个yield位置传值

    def func():
    print("水饺")
    a = yield "大馅水饺"
    print("a=", a)
    print("烧饼")
    b = yield "武大郎烧饼"
    print("b=", b)
    print("老婆饼")
    c = yield "只要老婆不要饼"
    print("c =",c)

    g = func()
    print("返回值是:",g.__next__())
    print("返回值是:",g.send("面条"))
    print("返回值是:",g.send("面条"))
    #print("返回值是:",g.send("面条")) #c = 面条 报错 StopIteration

    #结果
    水饺
    返回值是: 大馅水饺
    a= 面条
    烧饼
    返回值是: 武大郎烧饼
    b= 面条
    老婆饼
    返回值是: 只要老婆不要饼

    send()

    复制代码
     1 def func():
     2     print("水饺")
     3     a = yield "大馅水饺"
     4     print("a=", a)
     5     print("烧饼")
     6     b = yield  "武大郎烧饼"
     7     print("b=", b)
     8     print("老婆饼")
     9     c = yield "只要老婆不要饼"
    10     print("c =",c)
    11 
    12 g = func()
    13 print("返回值是:",g.__next__())
    14 print("返回值是:",g.send("面条"))
    15 print("返回值是:",g.send("面条"))
    16 #print("返回值是:",g.send("面条"))  #c = 面条  报错 StopIteration
    17   
    18 #结果
    19 水饺
    20 返回值是: 大馅水饺
    21 a= 面条
    22 烧饼
    23 返回值是: 武大郎烧饼
    24 b= 面条
    25 老婆饼
    26 返回值是: 只要老婆不要饼
    复制代码

    send和__next__的区别:

      send()和__next__都可以让生成器向下走一段,但send可以给上一个yield位置传值,使用时不能在第一次,也不能给最后一个yield传值

    二、推导式

    1、列表推导式

    语法:[ 结果  for循环  if判断 ]

    1 lst = ["中岛美雪","夏川美里","原由子","汪峰","田震","那英","周杰伦"]
    2 
    3 l = [name for name in lst if len(name) == 2  ] #这就是列表推导式
    4 print(l)
    1 lst = ["中岛美雪","夏川美里","原由子","汪峰","田震","那英","周杰伦"]
    2 
    3 l = [name for name in lst if len(name) == 2  ] #这就是列表推导式
    4 print(l)

    2、字典推导式

    语法:{ key:value  for循环  if判断 }

    dic ={"张无忌":"赵敏","杨过":"小龙女","郭靖":"黄蓉"}
    new_dic = {dic[k]: k for k in dic}   #字典推导式
    print(new_dic)
    new = {v:k for k,v in dic.items()}   #字典推导式
    print(new)
    dic ={"张无忌":"赵敏","杨过":"小龙女","郭靖":"黄蓉"}
    new_dic = {dic[k]: k for k in dic}   #字典推导式
    print(new_dic)
    new = {v:k for k,v in dic.items()}   #字典推导式
    print(new)

    3、集合推导式

    语法:{ 结果 for循环  if判断 }

    lst = [1,2,3,1,2,4]
    se = {k for k in lst}  #这是集合推导式
    print(se)     # {1,2,3,4}
    lst = [1,2,3,1,2,4]
    se = {k for k in lst}  #这是集合推导式
    print(se)     # {1,2,3,4}

    集合推导式自带去重功能

    5、没有元组推导式

    6、生成器表达式

    语法:( 结果 for循环  if判断 )  

    names = [['Tom',"Billy","Jefferson","Abdrew","Wesley","Steven","Joe"],['Alice',"Jill","Ana","Wendy",'Jennifer','Sherry','Eva']]

    name_gen = (name for el in names for name in el if name.count("e")==2)
    print(name_gen.__next__())
    print(name_gen.__next__())
    print(name_gen.__next__())


    结果
    #Jefferson
    #Wesley
    #Steven

    生成器表达式

    复制代码
     1 names = [['Tom',"Billy","Jefferson","Abdrew","Wesley","Steven","Joe"],['Alice',"Jill","Ana","Wendy",'Jennifer','Sherry','Eva']]
     2 
     3 name_gen = (name for el in names for name in el if name.count("e")==2)
     4 print(name_gen.__next__())
     5 print(name_gen.__next__())
     6 print(name_gen.__next__())
     7 
     8 
     9 结果
    10 #Jefferson
    11 #Wesley
    12 #Steven
    复制代码

    生成器拿值方式:

    1、用__next__和send

    2、使用for循环

    1 gen = (i for i in range(1,100) if i % 3 == 0)
    2 for num in gen:
    3  print(num)

    3、list(g),g是生成器

    1 gen = (i * i for i in range(100) if i % 3 == 0)
    2 print(list(gen))

    结果是一个列表

    [0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304, 2601, 2916, 3249, 3600, 3969, 4356, 4761, 5184, 5625, 6084, 6561, 7056, 7569, 8100, 8649, 9216, 9801]

    生成器的特性:

    1、节省内存

    2、惰性机制   (不到最后使用时不会拿值)  

    3、拿值只能往前,不能后退

    惰性机制+只能往前拿值特性的组合考察(深坑):

    复制代码
    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同理
    
    #结果
    111
    222
    []
    []
    复制代码

    **小知识  yield from**

    yield ffrom 可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回

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

    g = gen() #获取生成器
    for el in g:
    print(el)

    等价于:
    def gen():
    lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
    yield lst[0]
    yield lst[0]
    yield lst[0]
    yield lst[0]
    g = gen() #获取生成器
    for el in g:
    print(el)

    yield from

    复制代码
    def gen():
         lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
         yield from lst
    
    g = gen()  #获取生成器
    for el in g:
        print(el)
    
    等价于:
    def gen():
         lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
         yield  lst[0]
         yield  lst[0]
         yield  lst[0]
         yield  lst[0]
    g = gen()  #获取生成器
    for el in g:
        print(el)
    复制代码

    **面试题**

    1、

    复制代码
    def gen():
         lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
         lst2 = ["饼铛还是微星的好", "联想不能煮鸡蛋", "微星就可以", "还可以烙饼"]
         yield from lst    #yield from 会迭代返回列表中的元素,执行完lst才会执行lst2,所以不会有交替打印的效果
         yield from lst2
    g = gen()
    for el in g:
     print(el)
    效果:
    花藤
    胡辣汤
    微星牌饼铛
    Mac牌锅铲
    饼铛还是微星的好
    联想不能煮鸡蛋
    微星就可以
    还可以烙饼
    复制代码

     2、

    复制代码
    def add(a,b):
        return a + b
    def test():
        for r_i in range(4):
            yield r_i
    g = test()
    for n in [2,10]:
        g = (add(n,i) for i in g)
    print(list(g))
        #for循环第一次执行,n= 2时 g变为了 g = add(n,i) for i in (add(n,i) for i in test()  这时没取值,g也就不执行
        #  for第二次执行,n=10  此时 g= add(n,i) for i in (add(n,i) for i in test() 这时开始取值  ,g执行              
    
    结果:
    [20, 21, 22, 23]
    复制代码
  • 相关阅读:
    iOS8中用UIVisualEffectView实现高斯模糊视图(毛玻璃效果)
    IOS推荐学习网站
    Xcode因为证书问题经常报的那些错
    bug集合令
    html5的标签
    CSS小总结
    JS中的闭包
    前端之路宣告式
    linux安装mysql数据库
    yarn环境搭建
  • 原文地址:https://www.cnblogs.com/wuyufeng-9-14/p/10249530.html
Copyright © 2011-2022 走看看