Python 生成器

来源:互联网 发布:网络金融诈骗 编辑:程序博客网 时间:2024/05/20 20:21

生成器(generators):

       当需要一个庞大的列表数据时,用列表解析创建这样一个列表(列表解析,总是先生成列表,然后再执行其他内容,虽然这样消耗内存,降低性能),然后再当需要的时候,遍历列表获取列表中的元素,当数据量很大是, 就占用内存,降低性能;

       为了完善列表解析的性能上的弊端,引入了“生成器” 的概念:

生成器:

       当需要某一庞大的列表数据时,用生成器来代替列表解析,生成器并不首先生成所需的列表,而是在需要的时候才会计算出数据,来共调用者使用,因此,生成器没被调用时仅仅是占用很小内存的一个算法,并不包含数据,仅在生成器被调用时执行算法,并返回一个需要的数据。


列表解析表达式与生成器表达式: 区别仅仅是 [ ] 与 ( ) 的不同。

>>> list1 = [x for x in range(12)]   # 列表解析表达式>>> type(list1)<class 'list'>>>> generators1 = (x for x in range(12))    # 生成器表达式, x for x in range(12) 就是一个算法,只在调用时运行>>> type(generators1)<class 'generator'>
list1 可以用list的方法调用,但是generators1是生成器对象,只能用 next()方法调用:

>>> list1[2]2>>> list1[1]1>>> for i in list1:print(i, end=' ')0 1 2 3 4 5 6 7 8 9 10 11 >>> generators1<generator object <genexpr> at 0x0000000002BE0BA0>    # 生成器对象不含数据,仅仅是一个对象
>>> next(generators1)0>>> next(generators1)1>>> next(generators1)2>>> next(generators1
生成器除了 减少占用内存,提高性能外,最大的特点就是:中断、挂起并继续执行。

        中断、挂起,并保存上次运行状态,再重新开始。直到生成器(generators)产出所有的值,再次调用报错: StopIteration . 停止迭代。

>>> next(generators1)0>>> next(generators1)1>>> next(generators1)2>>> next(generators1)3>>> next(generators1)4>>> next(generators1)5>>> next(generators1)6>>> print(list1)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]>>> next(generators1)7>>> next(generators1)8>>> next(generators1)9>>> next(generators1)10>>> next(generators1)11>>> next(generators1)Traceback (most recent call last):  File "<pyshell#27>", line 1, in <module>    next(generators1)StopIteration>>> 

生成器的用法不仅仅局限于上面的例子:更广泛的应该是 生成器函数。

生成器函数:

        与其他函数的不同仅仅是增加了 一个关键字  yield  (产生)。

         return 在函数中的作用是: 返回值,并结束函数的运行。

         yield 在生成器函数中作用是:  产生一个值,并挂起函数的运行状态 ,等待再次运行。

         yield 就是专门给生成器用的 return

生成器的send() 方法:

          即然生成器可以 挂起 并保存运行状态(包括参数),那么就应该可以改变参数后,继续运行。send() 就起到这样的作用(传参)。

参考代码例子:

import randomdef get_data():    """返回0到9之间的3个随机数"""    return random.sample(range(10), 3)def consume():    """显示每次传入的整数列表的动态平均值"""    running_sum = 0    data_items_seen = 0    while True:        data = yield       # 挂起,等待传参,并赋值给data        data_items_seen += len(data)        running_sum += sum(data)        print('The running average is {}'.format(running_sum / float(data_items_seen)))def produce(consumer):    """产生序列集合,传递给消费函数(consumer)"""    while True:        data = get_data()        print('Produced {}'.format(data))        consumer.send(data)        yield      #  暂停挂起,等待再次被调用if __name__ == '__main__':    consumer = consume()    consumer.send(None)    producer = produce(consumer)    for _ in range(10):     # 循环10次        print('Producing...')        next(producer)     #  调用生成器函数
输出:

Producing...Produced [4, 0, 1]The running average is 1.6666666666666667Producing...Produced [5, 7, 8]The running average is 4.166666666666667Producing...Produced [2, 3, 1]The running average is 3.4444444444444446Producing...Produced [5, 7, 2]The running average is 3.75Producing...Produced [4, 0, 5]The running average is 3.6Producing...Produced [6, 4, 7]The running average is 3.9444444444444446Producing...Produced [7, 5, 2]The running average is 4.0476190476190474Producing...Produced [7, 0, 5]The running average is 4.041666666666667Producing...Produced [4, 1, 6]The running average is 4.0Producing...Produced [7, 8, 3]The running average is 4.2



这里先贴上参考文章链接:http://www.oschina.net/translate/improve-your-python-yield-and-generators-explained?lang=chs&page=1#


原创粉丝点击