昨天看赖勇浩的一篇文章,讲的是生成器(具体是哪篇后来找不到了 =.=),前两天又在看这方面的内容,就稍微总结下。
我们都知道,在Python中定义一个函数可以用def,如果函数需要返回一个结果可以用return value,而如果返回的是一个结果集,可以用Python的集合类型,如列表。这里我们假设以列表返回。当列表不是很大的时候,还是很方便的,而如果要返回的数据非常多,将其放在一个列表中,会占用比较大的内存空间。Python为了解决这个问题引入了生成器。生成器每次返回列表中的一个结果,而不是将整个列表一起返回。相对于前者,生成器速度会慢一些,但是占用的空间会小一些。生成器之于列表,就相当于range()之于xrange(),或者是readlines()之于xreadline()(xreadline()在2.7中貌似没有……)
函数返回值是用return,而生成器返回是用yield,“yield语句会将函数关起,并向它的调用者返回一个值,但是保存足够的状态信息为了让其能够在函数从它挂起的地方回复。这能够允许这些函数不断的产生一系列的值,而不是一次计算所有的值,之后将值以类似列表之类的形式来返回。”“不过生成器函数也许也有一个return语句,这个语句就是用来终止产生值的。”《Python学习手册》第三版P383
代码说的更清楚点
def gensquares(N):
for i in range(N):
yield i**2
x = gensquares(5)
gensquares()会生成0~N-1中每个数的平方,并依次返回,在IDLE中,print x会返回<generator object gensquares at 0x01202170>,而调用x.next()则会返回0~4的平方,第六次调用x.next()会返回StopIteration异常。
而这样单纯地用生成器只是返回生成器对象的地址,而不是一个集合,所以我们要把生成器放在列表解析里面,这样就有用多了:
for num in (x**2 for x in range(5)):
print num,
for num in [x**2 for x in range(5)]:
print num,
结果都是:0 1 4 9 16
注意:第一个函数用的是小括号,这样函数利用的就是生成器,而第二个是用的列表(这个例子有点囧,不过只为举例而用:),第一个的生成器形式是分5次依次返回0~4,而第二个列表形式是一次性返回[0, 1, 2, 3, 4]。这样可能看不出什么区别,但当返回的结果非常大时,生成器比列表占用的资源要少很多。
生成器同其他许多内置类型一样,支持迭代器,而其他很多支持迭代器的数据类型都可以产生生成器,这就是为什么遍历字典的时候不需要调用.keys(),遍历一个文件中的所有行不需要调用readlines()
for key in D:
print key, D[key]
for line in open('test.txt'):
print line,
PS:最近在看《Python学习手册》第三版,今天看到了模块一章,看的头昏脑胀,好像真的有点啰嗦了,看完写的这篇,好像我自己也变得啰嗦了 Orz....
PSS:初学Python,有错误的话请各位指出。