zoukankan      html  css  js  c++  java
  • 自学Python4.7-生成器(方式一:生成器函数)

    自学Python之路-Python基础+模块+面向对象
    自学Python之路-Python网络编程
    自学Python之路-Python并发编程+数据库+前端
    自学Python之路-django

    自学Python4.7 - 生成器(方式一:生成器函数)

    定义:生成器(generator)是一个包含yield关键字的函数,当它被调用的时候,在函数体中的代码不会被执行,而是会返回一个迭代器。
              (一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);      
                  如果函数中包含yield语法,那这个函数就会变成生成器;)

    • 生成器是一个特殊的程序,可以被用作控制循环的迭代行为
    • 生成器类似于返回值为数组的一个函数,这个函数可以接收参数,可以被调用,但是,不同于一般的函数会一次性返回包含了所有数值的数组,生成器一次 只产生一个值,这样消耗的内粗数量大大减少,而且允许调用函数可以很快的开始处理前几个返回值。因此,生成器看起来像一个函数但是表现的却像一个迭代器

    python提供了两种基本的生成器方式:

    • 生成器函数:也是用def来定义,利用关键字yield一次返回一个结果,阻塞,重新开始
                           每次请求一个值,就会执行生成器中的代码,知道遇到一个yield或者return语句
                           ①yield语句意味着应该生成一个值
                           ②return语句意味着要停止执行(不生成任何东西,只有在一个生成器中使用时才能进行无参数调用)
    • 生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果

    1.  生成器函数:  

          为什么叫生成器函数?因为他随着时间的推移生成了一个数值队列。一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,然后重新拾起继续执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可以使函数继续执行。
         生成器和迭代协议是密切相关的,可迭代的对象都有一个__next()__成员方法,这个方法要么返回迭代的下一项,要么引起异常结束迭代。
         为了支持迭代协议,拥有yield语句的函数被编译为生成器,这类函数被调用时返回一个生成器对象,返回的对象支持迭代接口,即成员方法__next()__继续从中断处执行执行。

    def func():   #func是函数称为生成器,当执行此函数func()时会得到一个迭代器。
        yield 1
        yield 2
        yield 3
        yield 4
    temp = func()
    print(temp.__next__())
    print(temp.__next__())
    print(temp.__next__())
    print(temp.__next__())

    def creat_counter(n):
        print('create counter')
        while True:
            yield n
            print('increment n')
            n += 1
    cnt = creat_counter(2)
    print(cnt)
    print(next(cnt))
    print(next(cnt))
    print(next(cnt))

    分析以上的列子:

    • 在create_counter函数中出现了关键字yield,预示着这个函数每次只产生一个结果值,这个函数返回一个生成器(通过第一行输出可以看出来),用来产生连续的n值
    • 在创造生成器实例的时候,只需要像普通函数一样调用就可以,但是这个调用却不会执行这个函数,这个可以通过输出看出来
    • next()函数将生成器对象作为自己的参数,在第一次调用的时候,他执行了create_counter()函数到yield语句,返回产生的值2
    • 我们重复的调用next()函数,每次他都会从上次被挂起的地方开始执行,直到再次遇到了yield关键字
    def cube(n):
        for i in range(n):
            yield i ** 3
    for i in cube(5):
        print(i)
    

    从理解函数的角度出发我们可以将yield类比为return,但是功能确实完全不同,在for循环中,会自动遵循迭代规则,每次调用next()函数,所以上面的结果不难理解。

    举例1:

    举例2:

    举例3: 取不到值会报错

     

    举例4: 使用for循环取值

     

    举例5.1  : 打印出10个哇哈哈

     

    举例5.2如果现在有10个哇哈哈, 我现在只想用5个

    迭代器依旧延续向下走:

    举例6

    def generator():
        print('123')
        content = yield 1
        print('=========',content)
        print(456)
        yield 2
    g = generator()
    ret = g.__next__()
    print("******",ret)
    ret = g.send("hello")
    print("**********",ret)
    

    send 获取下一个值的效果和next基本一致,只是在获取下一个值得时候,给上一个yield的位置传递一个数据

    使用send的注意事项:

    • 第一次使用生成器的时候,是用next获取下一个值
    • 函数最后一个yield不能接受外部的值

    举例7.1:
    获取移动平均值:
    10   20   30   10 
       15  20   17.5

    def average():
        sum = 0
        count = 0
        avg = 0
        while True:
           num = yield avg
           sum += num
           count += 1
           avg = sum/count
    
    avg_g = average()
    avg_g.__next__()
    avg1 = avg_g.send(10)
    avg1 = avg_g.send(20)
    avg1 = avg_g.send(30)
    print(avg1)
    

    举例7.2:   预激生成器的装饰器完成获取移动平均值

    def init(func):   #装饰器
        def inner(*args,**kwargs):
            g = func(*args,**kwargs)    #g = average()
            g.__next__()
            return g
        return inner
    
    @init
    def average():
        sum = 0
        count = 0
        avg = 0
        while True:
            num = yield avg
            sum += num    # 10
            count += 1    # 1
            avg = sum/count
    
    avg_g = average()   #===> inner
    ret = avg_g.send(10)
    print(ret)
    ret = avg_g.send(20)
    print(ret)

    以上程序执行步骤:

    举例8 :

    在python3里面的新功能 yield from 

     

    .

  • 相关阅读:
    分享一些优化博客的心得
    HTTP相关整理(上)
    正则&highlight高亮实现(干货)
    通过一个demo了解Redux
    升级ChinaCock10.3.3激情版3注意事项
    解决uniDAC超时问题:已超过了锁请求超时时段。
    kbmMWSmartBind实现ListView绑定数据集进阶篇(一)
    通过输出日志到文件来检查app闪退原因
    VertScrollBox不能滑动
    使用kbmMW SmartBinding经验几则
  • 原文地址:https://www.cnblogs.com/yaoyaojcy/p/10575960.html
Copyright © 2011-2022 走看看