• Python 生成器总结


    生成器的概念:
    生成器不会把结果保存在一个系列中,而是保存在生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束
    生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
    生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

    生成器的特点:
         生成器是一个函数,而且函数的参数都会保留。
         迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的

    生成器语法
    生成器表达式: 通列表解析语法,只不过把列表解析的[]换成()
    生成器表达式能做的事情列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存。

    生成器函数: 在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数。

    在Python中,yield就是这样的一个生成器。

    yield 生成器的运行机制:

    当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把 yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态。开始运行,直至出现yield语句,把参数给你,之后停下。如此反复 直至退出函数。

    yield的使用

    在Python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器,它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常 所用return语句那样,能得到结果值。如果想取得值,那得调用next()函数


    下面以斐波拉契为例:

    #coding:utf8
    def fib(max): #10
        n, a, b = 0, 0, 1
        while n < max: #n<10
            #print(b)
            yield b
            a, b = b, a + b
    
            n += 1
        return 
    
    f = fib(10)
    for i in f:
        print f
    

    从上面的运行机制描述中,可以获知,程序运行到yield这行时,就不会继续往下执行。而是返回一个包含当前函数所有参数的状态的iterator对象。目的就是为了第二次被调用时,能够访问到函数所有的参数值都是第一次访问时的值,而不是重新赋值。

    程序第一次调用时:

    def fib(max): #10
        n, a, b = 0, 0, 1
        while n < max: #n<10
            #print(b)
            yield b   #这时a,b值分别为0,1,当然,程序也在执行到这时,返回
            a, b = b, a + b
    

    程序第二次调用时:

    从前面可知,第一次调用时,a,b=0,0,那么,我们第二次调用时(其实就是调用第一次返回的iterator对象的next()方法),程序跳到yield语句处,

    执行a,b = b, a+b语句,此时值变为:a,b = 0, (0+1) => a,b = 0, 1

    程序继续while循环,当然,再一次碰到了yield a 语句,也是像第一次那样,保存函数所有参数的状态,返回一个包含这些参数状态的iterator对象。

    等待第三次的调用....

     

    通过上面的分析,可以一次类推的展示了yield的详细运行过程了!

    通过使用生成器的语法,可以免去写迭代器类的繁琐代码,如,上面的例子使用迭代类来实现,代码如下:

    #coding:UTF8
    
    class Fib:  
        def __init__(self, max):  
            self.max = max
            print self.max
        def __iter__(self):  
            self.a = 0  
            self.b = 1 
            self.n = 0 
            return self  
        def next(self):  
            fib = self.n  
            if fib >= self.max:  
                raise StopIteration  
            self.a, self.b = self.b, self.a + self.b  
            self.n += 1
            return self.a
        
    f = Fib(10)
    for i in f:
        print i
    

    yield 与 return

    在一个生成器中,如果没有return,则默认执行到函数完毕时返回StopIteration;

     如果遇到return,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。

    如果在return后返回一个值,会直接报错,生成器没有办法使用return来返回值。

    生成器支持的方法(借鉴别人的例子,感觉蛮好的)

         close(...)
     |      close() -> raise GeneratorExit inside generator.
     |  
     |  next(...)
     |      x.next() -> the next value, or raise StopIteration
     |  
     |  send(...)
     |      send(arg) -> send 'arg' into generator,
     |      return next yielded value or raise StopIteration.
     |  
     |  throw(...)
     |      throw(typ[,val[,tb]]) -> raise exception in generator,
     |      return next yielded value or raise StopIteration.
    

    close()

    手动关闭生成器函数,后面的调用会直接返回StopIteration异常。

    #coding:UTF8
    
    def fib():
        yield 1
        yield 2
        yield 3
    
    f = fib()
    print f.next()
    f.close()
    print f.next()
    

    send()

    生成器函数最大的特点是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。
    这是生成器函数最难理解的地方,也是最重要的地方,

    def gen():
        value=0
        while True:
            receive=yield value
            if receive=='e':
                break
            value = 'got: %s' % receive
     
    g=gen()
    print(g.send(None))     
    print(g.send('aaa'))
    print(g.send(3))
    print(g.send('e'))
    

    执行流程:

    1. 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置。此时,执行完了yield语句,但是没有给receive赋值。yield value会输出初始值0注意:在启动生成器函数时只能send(None),如果试图输入其它的值都会得到错误提示信息。
    2. 通过g.send(‘aaa’),会传入aaa,并赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句有停止。此时yield value会输出”got: aaa”,然后挂起。
    3. 通过g.send(3),会重复第2步,最后输出结果为”got: 3″
    4. 当我们g.send(‘e’)时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。

    最后的执行结果如下:

    0
    got: aaa
    got: 3
    Traceback (most recent call last):
      File "1.py", line 15, in <module>
        print(g.send('e'))
    StopIteration
    

     

    throw()

    用来向生成器函数送入一个异常,可以结束系统定义的异常,或者自定义的异常。
    throw()后直接跑出异常并结束程序,或者消耗掉一个yield,或者在没有下一个yield的时候直接进行到程序的结尾。

    def gen():
        while True: 
            try:
                yield 'normal value'
                yield 'normal value 2'
                print('here')
            except ValueError:
                print('we got ValueError here')
            except TypeError:
                break
     
    g=gen()
    print(next(g))
    print(g.throw(ValueError))
    print(next(g))
    print(g.throw(TypeError))
    

    执行流程:

    1. print(next(g)):会输出normal value,并停留在yield ‘normal value 2’之前。
    2. 由于执行了g.throw(ValueError),所以会跳过所有后续的try语句,也就是说yield ‘normal value 2’不会被执行,然后进入到except语句,打印出we got ValueError here。然后再次进入到while语句部分,消耗一个yield,所以会输出normal value。
    3. print(next(g)),会执行yield ‘normal value 2’语句,并停留在执行完该语句后的位置。
    4. g.throw(TypeError):会跳出try语句,从而print(‘here’)不会被执行,然后执行break语句,跳出while循环,然后到达程序结尾,所以跑出StopIteration异常。

      

  • 相关阅读:
    map初始化
    map
    sort排序
    455分发饼干
    392判断子序列
    vector遍历
    vector删除数据
    VC-进程间通信(InterProcess Communication,IPC)
    Oracle 11g 安装和登录(windows)
    控制台输出宽字符wchar_t的中文显示问题
  • 原文地址:https://www.cnblogs.com/qianyuliang/p/7161538.html
Copyright © 2020-2023  润新知