zoukankan      html  css  js  c++  java
  • 【python】生成器和生成器函数

    1、生成器函数:

    普通函数:

    def func():

        print("周杰伦")

        return "昆凌"  

    func() #执行func()函数,"周杰伦"

    print(func())  #执行结果:昆凌

    生成器函数:

    def func():

        print("周杰伦")

        yield "昆凌"  # 函数中包含了yield, 当前这个函数就不再是普通的函数了. 是生成器函数

    func() #通过func()函数生成一个生成器,非执行,没结果

    print(func()) #打印的是该生成器函数所在的内存地址

    #return 和yield的区别:

    return: 执行到return时函数结束执行

    yield:函数分段执行,从(当前yield到下一个yield]的内容

    举例:

    def func():

        print("周杰伦")

        yield "昆凌" 

        print("王力宏")

        yield "李云迪" 

        #print("大家好才是真的好")  #最后一个yield后不要写东西,因为__next__()找不到下一个yield时会报错StopIteration

    g=func() #生成一个生成器

    print(g.__next__()) #周杰伦 昆凌

    print(g.__next__()) #王力宏 李云迪

    2、send()

    #__next__()和send()区别:

    __next__() 可以让生成器向下执行一次;

    send() 也可以让生成器向下执行一次, 给上一个yield传一个值, 第一个和最后一个yield不需要传值(最后一个值可以传进去但会报错)。

    举例1:

    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)

    执行结果:

    我吃什么啊

    馒头--------------第一次__next__()获取的内容

    a= 胡辣汤----第一次send赋值,并打印

    大饼-------第一次send获取的内容

    b= 狗粮---第二次send赋值

    韭菜盒子---第二次send获取的内容

    c= 猫粮

    GAME OVER

     

    举例2:

    def func():

        print('0')

        yield 1

        print('2')

        yield 3

        yield 4

    g1 = func()

    lst = list(g1)  #把生成器转换成列表

    print(lst)

    执行结果:

    0

    2

    [1, 3, 4]

    3、列表推倒式

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

    lst = [i for i in range(1,101) if i%2==0]

    print(lst)

    4、生成器表达式

    #生成器表达式和列表推倒式基本是一样的,只是把[]换成()

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

    g = (i for i in range(10))

    print(g) #打印的是通过表达式生成的生成器所在的内存地址

    print(g.__next__()) #获取的第一个元素是0

    print(list(g)) #获取的是列表 [0,1,2,3,4,5,6,7,8,9]

    5、其他推倒式

    5.1 字典推倒式:

    语法:[结果(key:value) for 变量 in 可迭代对象 if 筛选]

    #把字典中的key:value互换 .{"b":"a", "d":"c"}

    dic = {"a":"b", "c":"d"}

    new_dic = {dic[key]:key for key in dic}

    print(new_dic)

    5.2 集合推倒式:

    语法:{结果(key) for 变量 in 可迭代对象 if 筛选}

    lst = ["马化腾", "马化腾", "王建忠", "张建忠", "张雪峰", "张雪峰"]

    s = {i for i in lst}    # 集合推倒式,无序且不重复,自动去重

    print(s)

    注:没有元组推倒式(因为元组不可变,小括号括起来的是生成器表达式)

    总结:

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

    2、生成器3种生成方法:

            1)通过生成器函数

            2)通过生成器表达式

            3)通过数据转换

    3、生成器函数被执行,如func()是拿到一个生成器函数,不是获取里面的内容

    4、生成器取值:

      1)__next__()

      2)send()

      3)for循环

      4)list(g)

    5、return 和yield的区别:

      return: 执行到return时函数结束执行

      yield:函数分段执行,从(当前yield到下一个yield]的内容

    6、生成器惰性机制应用

    举例1:

    def func():

        print(111)

        yield  222

    g = func() #生成器g

    g1 = (i  for i in  g) #生成器g1,但数据来源g

    g2 = (i  for i in  g1)#生成器g2,但数据来源g1

    print(list(g)) #获取生成器g数据,此时func()才会被执行,打印111,获取到222

    print(list(g1))#获取g1数据,来源g,但g数据已被取完,所以返回是空

    print(list(g2))#同g1

    执行结果:

    111

    [222]

    []

    []

    举例2:若把print(list(g))注释了,得到的结果怎样?

    def func():

        print(111)

        yield  222

    g = func() #生成器g

    g1 = (i  for i in  g) #生成器g1,但数据来源g

    g2 = (i  for i in  g1)#生成器g2,但数据来源g1

    #print(list(g)) 

    print(list(g1))

    print(list(g2))

    执行结果:

    111

    [222]

    []

    举例3:

    def add(a,b):

        return a + b

    def test():

         for i in range(4):

             yield i

    g = test() #0,1,2,3,

    for n in [2,10]: #n 取值2,10 表示共循环2次

        g=(add(n,i) for i in g)

    print(list(g)) 

    #list(g)时才会执行,生成器惰性特质

    #g=(add(n,i) for i in g) 循环2次,相当于最后g=(add(n,i) for i in (add(n,i) for i in g))

    #g=(add(n,i) for i in (add(n,i) for i in (0,1,2,3)))

    #生成器不到最后不执行,最后一次n=10,那么g=(add(10,i) for i in (10,11,12,13))

    #g=[20,21,22,23]

     

  • 相关阅读:
    冲印数码照片的奥秘
    买手机(一)
    情人节的考验
    一日三茶
    追寻童年的乐趣在PSP上玩童年玩过的街机游戏
    转贴:常用的美国俚语
    用左手画CAD
    桃花朵朵开春游南汇桃花节
    不用GPRS照样用手机上网以后手机费不能报销的朋友们也能用手机上网啦!
    双休日去爬山
  • 原文地址:https://www.cnblogs.com/xlzhangq/p/13211155.html
Copyright © 2011-2022 走看看