zoukankan      html  css  js  c++  java
  • Python-生成器

    创建生成器

      创建生成器需要两部步骤

    1. 定义一个包含yield语句的函数
    2. 调用第一步创建的函数得到生成器
    def test(val,step):
      2     print("函数开始执行")
      3     cur = 0
      4     for i in range(val):
      5         cur += i * step
      6         yield cur
      7 

    yeild cur 语句的两个作用:

    1. 每次返回一个值,有点类似与return语句
    2. 冻结执行,程序每次执行到yield语句时就会停止运行

    在程序被冻结时,当程序调用next()函数获取生成器的下一个值时,程序才会继续向下执行

    需要注意的是,当程序调用含yeild的函数时,并不会立即执行,它只是返回一个生成器。

    if __name__ == "__main__":
      9     #此时程序并不会立即运行
     10     t = test(10,2)
     11     #获取生成器的第一个值
     12     print(next(t))#生成器被冻结在yield处                   
     13     print(next(t))

     运行结果:

    函数开始执行
    0
    2
    从运行结果可以看出,当程序执行 t = test(10,2)时,程序并没有开始执行test()函数,当程序第一次调用next(t)时,test()函数才开始执行。当程序调用next(t)时,生成器会返回yield cur 语句返回的值,程序被冻结在yield语句处,所以可以看到生成器第一次输出的值是0

    当程序第二次调用next(t),程序的“冻结”被解除,继续向下执行。

    程序可以用for循环来遍历生成器,相当于不断的使用next()函数来获取生成器的值。

    for ele in t:
           print(ele,end = "	")

    程序运行结果

    6       12      20      30      42      56      72      90
    由于前面两次调用next()已经获取了生成器的前两个值,所以循环第一次输出的值为6

    程序也可以使用list()或者tuple()将生成器能生成的值转换成列表或者元组

     17     t1 = list(test(10,1))
     18     print(t1)
     19     t2 = tuple(test(10,1))
     20     print(t2) 

    程序运行结果

    函数开始执行
    [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
    函数开始执行
    (0, 1, 3, 6, 10, 15, 21, 28, 36, 45)
    python主要提供两种方法来创建生成器

    1. 使用for循环的生成器推导式
    2. 调用带yield语句的生成器函数

     生成器是python的一个特色功能,在其他语言中往往没有对应的机制,生成器具有以下优势

    1. 当使用生成器来生成多个数据时,程序是按需获取数据的,它不会一开始酒吧所有数据都生成出来,而是next()获取下一个数据时,生成器才会执行一次,因此可以减少代码的执行次数。
    2. 当函数需要返回多个数据时,如果不使用生成器,程序就会使用列表或元组来收集函数返回的多个值,当函数要返回的数据亮比较大时,这些列表和元组会带来一定的内存开销。
    3. 使用生成器会使代码跟家简洁。

    生成器的方法

    当生成器运行起来后,开发者还可以为生成器提供值,通过这种方法让生成器与外部程序进行动态的数据交换

    1. 外部程序通过send()方法发送数据
    2. 生成器函数使用yield语句接收数据

    只有等到程序被冻结之后,外部程序才能使用send()方法向生成器发送数据。获取生成器第一次生成的值,应该使用next()函数。如果程序非要用send()来获取生成器第一次生成的值,则不能向生成器发送数据,只能传入None参数。

      7 def square(val):
      8     i = 0
      9     out_val = None
     10     while True:
     11         #使用yield语句生成值,使用out_val来接受send()发送的
        参数值
     12         out_val = (yield out_val ** 2) if out_val is not No    ne else (yield i ** 2)
     13         #如果程序使用send()方法获取生成器的下一个值,out_va    l会获取send()方法的参数值
     14         if out_val is not None:
     15             print("%d" % out_val)
     16         i += 1

    运行结果

    0
    1
    9
    81
    9

    上面程序第一次使用send()方法来获取生成器的下一个值,只能传入None参数。当程序冻结时,并没有给out_val进行赋值,根据运行结果可以看出第一次生成器的值为0。接下来调用next()函数获取生成器的下一个值,程序从冻结处(对out_val进行赋值)向下执行,out_val被赋值为None,所以程序执行yield i ** 2,生成器返回的结果为1,程序再次被冻结。

    接下来程序调用send(9),程序从冻结处向下运行(给out_val进行赋值),此时out_val被赋值为9,生成器返回值为81

    接下来程序调用next(),out_val被赋值为None,此时程序执行yield i ** 2,此时i的值已经递增为3,生成器返回的值为9

    笨鸟先飞
  • 相关阅读:
    ESP8266-12F引脚接法
    esp8266物联网开发六:让ESP32-CAM五彩斑斓
    esp8266物联网开发五:SSL保驾护航
    esp8266物联网开发四:MQTT再论部控
    esp8266物联网开发三:MQTT初窥貌容
    esp8266物联网开发二:Arduino名门正派
    esp8266物联网开发一:MicroPython初战江湖
    一些错误记录
    jimdb压测踩坑记
    Caffeine批量加载浅析
  • 原文地址:https://www.cnblogs.com/zoutingrong/p/12787259.html
Copyright © 2011-2022 走看看