zoukankan      html  css  js  c++  java
  • python记录_day12 生成器

    什么是生成器?

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

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

    1、通过生成器函数

    2、通过生成器表达式

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

    一、 生成器函数

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

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

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

    1、通过__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,所以报错
    __next__()

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

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

     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()

    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)
    View Code

    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)
    字典推导式

    3、集合推导式

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

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

    集合推导式自带去重功能

    5、没有元组推导式

    6、生成器表达式

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

     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

    **面试题**

    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]
  • 相关阅读:
    SPOJ 694 (后缀数组) Distinct Substrings
    POJ 2774 (后缀数组 最长公共字串) Long Long Message
    POJ 3693 (后缀数组) Maximum repetition substring
    POJ 3261 (后缀数组 二分) Milk Patterns
    UVa 1149 (贪心) Bin Packing
    UVa 12206 (字符串哈希) Stammering Aliens
    UVa 11210 (DFS) Chinese Mahjong
    UVa (BFS) The Monocycle
    UVa 11624 (BFS) Fire!
    HDU 3032 (Nim博弈变形) Nim or not Nim?
  • 原文地址:https://www.cnblogs.com/zhang-yl/p/9890867.html
Copyright © 2011-2022 走看看