深度实践OpenStack:基于Python的OpenStack组件开发—3.5.5 生成器

举报
华章计算机 发表于 2019/06/06 12:05:32 2019/06/06
【摘要】 本书摘自《深度实践OpenStack:基于Python的OpenStack组件开发》——书中第3章,3.5.5节,作者是喻涛、田亮、张家龙、赵利军、李飞。

3.5.5 生成器

下面首先给出生成器的定义:生成器是一次生成一个值的特殊类型函数,可以将其视为可恢复函数。调用该函数将返回一个可用于生成连续 x 值的生成器。

这个定义比较绕口,下面来做一个形象的比较。

int get_next()

{

static int number = 1; return number++;

}

上边是一段简单的c语言代码,它的功能是只要程序不退出,就一直返回静态变量 number+1的值。由于number是有static修饰的,因此,每一次调用get_next函数返回的值都不一样。Python生成器的功能类似以上的这个函数。下面介绍如何构造一个生成器:

方法1:

def first_generator(): 

    yield "hello"

方法2:

def generator_fib(n):

    first = 0

    second = 1

    for x in xrange(n):

        first,second = second,first+second 

        yield first

以上的代码中用到一个新的关键字:yield。在Python中使用了yield关键字的函数一定是一个生成器。yield关键字表示返回当前的值,但是保存当前所有变量及其内存状态,当下一次代码被调用时,返回原有的内存状态。

方式1中的first_generator函数比较简单,每次调用时,都只是返回“hello”字符串。但是,这个函数和def hello():return “hello”有本质区别,例如:

type(hello()) ====><type 'str'>

type(first_generator()) ====><type 'generator'>

调用hello这个方法之后,返回的是一个计算之后的值;而调用first_generator之后,返回的是一个计算表达式,真正获取它的值需要调用next方法,或者在for循环中直接进行迭代。

方式2中的generator_fib函数返回的是一个生成器,这个生成器的作用是返回0~n之间的斐波那契数列。

前面讲了如何构造一个生成器,那这个生成器怎么使用?

result = first_generator() 

for res in result:

    print res


result = generator_fib(10) 

for res in result:

    print res


result = first_generator() 

result.next()

result = generator_fib(10) 

result.next()

当使用next方法的时候,执行到生成器的末尾会产生StopIteration异常。


下面学习如何使用其他方式创建生成器。我们把前面所学的列表推导:

list_test = [x for x in xrange(10)]

修改一下,就成为了生成器:

list_test = (x for x in xrange(10))

同样地,也可以把文件对象改造成生成器:

file_obj = open(file_path,mode) 

file_generator = (line for line in file_obj)

简单的生成器就讲到这里,而生成器的作用也不仅仅是实现循环这么简单。例如,可以使用生成器来实现cat file | grep keyword这样一个Linux命令的功能,有兴趣的可自行练习一下相关的内容。

总结:使用生成器和使用其他可迭代的数据类型非常相似,不同的地方在于内存的处理方式。生成器的执行结果并没有在内存中立即展开,而是在执行结果被调用时才进行展开,因此,从内存消耗角度上看,生成器更加节省。

为此,提出Python性能优化的第八条原则:在不影响可读性的原则上,建议使用生成器以节省内存,尤其是在处理需要大量内存的操作时。

同时需要注意的是()的用法,我们知道tuple也是使用()定义的,并且,函数和方法也都采用了(),因此,()到底表示的是什么,需要根据上下文的语境来考虑:出现在def关键字同一行,表示定义方法或者函数;和“,”一起使用,表示构造tuple;和列表推导式一起使用,表示构造生成器。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。