zoukankan      html  css  js  c++  java
  • python——生成器

    1.什么是生成器:可以理解为一种数据类型,这种数据类型实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__ 方法),所以生成器就是可迭代对象

    2.生成器分类在python中的表现形式:(python有两种不同的方式提供生成器)

      (1)生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中,挂起函数的状态,以使下次从他离开的地方继续执行

    def test():
        print('开始生孩子了')
        yield ''
        print('开始生儿子了')
        yield '儿子'
        yield '孙子'
    
    
    res = test()                            res调用了次函数,此时res就相当于一个生成器,支持__next__方法,同时也可以用for循环去遍历它 即 for i in res:print(i) 会将所有内容打印(生孩子---孙子)        
    print(res)
    print(res.__next__())              
    print(res.__next__())
    运行结果:
    <generator object test at 0x00000198BF0A30F8>        调用函数,相当于返回一个地址  (生成器)   需要通过res.__next__()来显示
    开始生孩子了                           
    我
    开始生儿子了
    儿子                                从运行结果可以得知,yield返回了一个值,相当于return,其与return不同之处在于yield会保存当前函数的运行状态,所以第二次运行print(res.__next__())
                                      是从print(‘开始生儿子了’)开始,并在yield ‘儿子’ 处停止并返回值

          卖包子实例

    def pro_baozi():
        for i in range(100):
            print('正在生产包子')
            yield '第 %s屉包子生产出来了' %i
            print('
    ')
            print('第 %s屉包子卖出去了'%i)
    
    pro_g = pro_baozi()               pro_g调用了函数,此时pro_g就可看作是一个生成器,此时它支持__next__方法
    baozi1 =print(pro_g.__next__())
    baozi1 =print(pro_g.__next__())
    baozi1 =print(pro_g.__next__())
    运行结果:
    正在生产包子
    第 0屉包子生产出来了        函数运行到第一个 yield 暂停并返回值,第二次运行从当前位置开始直到再一次碰到 yield 暂停并返回值
                      此处开始到下一次换行前是第二次调用的结果,因为yield会保留函数的运行状态,所以在第二次调用后,先执行print('
    '),因为print自带换行,因此执行此语句换行了两次
    
    第 0屉包子卖出去了
    正在生产包子
    第 1屉包子生产出来了
    
    
    第 1屉包子卖出去了
    正在生产包子
    第 2屉包子生产出来了

      (2)生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

        三元表达式

    name = '焦国华'
    res = '帅哥'   if name == '焦国华'  else  '沙雕'        这种形式就是三元表达式    res = True if 条件  else False
    print(res)  
    运行结果:

    帅哥

    
    

        列表解析

    l = ['鸡蛋%s' %i for i in range(10)]      这种形式就称为列表解析,实际上也是[ ]内是一个二元表达式   也可以写为 l = ['鸡蛋%s' %i for i in range(10)  if i >5]   运行输出['鸡蛋 0', '鸡蛋 1', '鸡蛋 2', '鸡蛋 3', '鸡蛋 4']
    print(l)
    运行结果:['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

        总结:

        (1)生成器表达式   把列表解析的 [ ] 换成()得到的就是生成器表达式

    laomuji = ('鸡蛋%s' %i for i in range(10))    此处只是获取了一个生成器,laomuji是一个内存地址,只有再对其进行迭代操作才会输出值,不像三元表达式一样
    print(laomuji)
    print(laomuji.__next__())
    print(laomuji.__next__())
    运行结果:
    <generator object <genexpr> at 0x000001AFF8B8F048>
    鸡蛋0
    鸡蛋1

        (2)列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

        (3)python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是用迭代器协议访问对象。例如,sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了

          迭代器协议,所以,我们可以直接这样计算一系列值的和:

    sum(x ** 2   for x in range(4))      即内部可以直接写一个生成器表达式,因为生成器表达式满足迭代器协议

     

    def get_pop():
        with open('人口普查','r',encoding = 'utf8') as f:
            for i in f:
                yield i
    
    g = get_pop()
    all_pop = sum(eval(i)['population']    for i in g)        生成器表达式,前边的是要相加的数。 for i in g 拿到的是字符串形式如‘{'name': '北京','population':'131'}’,通过eval函数
                                          使其变成对应的字典形式,在通过key索引,得到人口数,进而进行相加

         

        而不用多此一举先构造一个列表

    sum([x ** 2   for x in range(4)])

    3.生成器总结:

      (1)语法上和函数类似:生成器函数和常规函数几乎是一样的,他们都是使用def语句进行定义,差别在于,生成器使用 yield 语句返回一个值,而常规函数使用 return 语句返回一个值

      (2)自动实现迭代器协议:对于生成器,python会自动实现迭代器协议,以便应用到迭代背景中(如for循环、sum()函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的__next__

        方法,并且,在没有值可以返回的时候,生成器自动生成StopIteration异常

      (3)状态挂起:生成器使用yield语句返回一个值,yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从离开他的地方继续执行

    优点::(1)生成器的好处是延时计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这回与大数据量处理将会非常有用

        (2)生成器还能有效提高代码可读性

      (4)生成器只能遍历一次

  • 相关阅读:
    dubbo和spring的@service注解区别
    mybatisplus乐观锁
    mybatis中llike模糊查询中#和$的使用,以及bind标签的使用
    mybatis的两个内置参数
    mybatis返回主键
    mybatis使用foreach进行批量保存
    jsp自定义标签
    java.lang.ClassNotFoundException:oracle.jdbc.OracleDriver
    junit测试框架
    junit断言和junit注释assert
  • 原文地址:https://www.cnblogs.com/jgua/p/13514882.html
Copyright © 2011-2022 走看看