1. 生成式和生成器
列表生成式是python受欢迎的一种语法之一,通过一句简洁的语法,就能对元组元素进行过滤,还可以对得到的元素进行转换处理。
语法格式:
[exp for val in collection if condition]
相当于
result = []
for val in collection:
if (condition):
result.append(exp)
例子:
a = [x*x for x in xrange(10) if x%2 == 0]
print (type(a))
print (a)
结果:
<type 'list'>
[0, 4, 16, 36, 64]
解释:
① 由此取出xrange(10)从0到9
② 判断 x*x 是偶数,就保留,存在新的字典中
③ 把所有符合x*x是偶数的元素都放到新的列表中返回。
通过列表生成式,我们可以创建一个列表,但是,受到内存限制,列表容量肯定是有限的;
如果创建一个包含100万个元素的的列表,不仅占用很大的存储空间,当我们仅仅需要访问前面的几个元素,后面绝大多数元素占的空间都浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素?
这样一来就不必创建完整的list了,从而节省大量的空间。
在python中,这种一边循环一边计算的机制,称为"生成器"(Generator)
生成器是一次生成一个值的特殊类型函数,可以将其视为可恢复函数,调用该函数将返回一个可用于生成连续 x 的值的生成器;
简单的说就是在函数执行过程中,yield 语句会把你需要的的值返回给调用生成器的地方,然后退出函数,下次调用生成器函数
的时候,又从上次中断的地方开始执行,而生成器内的所有变量参数会被保存下来供下一次使用。
要创建生成器有好几种方法:
第一种方法
把一个列表生成式的[],改成(),这就创建了一个生成器。
例子:
lst = (x*x for x in xrange(1,101) if x%2 == 0)
print (lst)
print (type(lst))
print (lst.next())
print (lst.next())
print (lst.next())
print (lst.next())
print (lst.next())
print (lst.next())
结果:
<generator object <genexpr> at 0x02E72508>
<type 'generator'>
4
16
36
64
100
144
解释:
generator 保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素为止。
第二种方法:
函数中定义列表生成器,即如果函数中包含yield关键字,那么这个函数不再是一个普通函数,而是一个generator。
普通函数:
def func(n):
sum = 0
i = 0
while(i<n):
sum = sum + i
i += 1
print (sum)
func(10)
结果:
0
1
3
6
10
15
21
28
36
45
列表生成器:
def func(n):
sum = 0
i = 0
while(i<n):
sum = sum + i
i += 1
yield (sum)
for x in func(10):
print x
print (type(func(10)))
结果:
0
1
3
6
10
15
21
28
36
45
解释:
① 以上函数有关键字 yield ,所以生成的是一个生成器;
② 通过for 循环调用生成器,当执行到yield的时候,返回sum值,sum为0,此时暂停并记录sum的值;
③ 打印出sum的值,然后继续往下去执行,跳入下一个循环 while(1<10)
④ 直到遇到yield的时候,返回sum的值
⑤ 反复执行3,4的步骤,直到循环结束,最终退出程序。
两个函数的区别:
一个直接反回了表达式的结果列表,另一个是一个对象,该对象包含了对表达式结果的计算引用,通过循环可以直接输出。
生成器不会一次性列出所有数据,当你用到的时候,再列出来,更加节约内存使用率。
普通函数和列表生成器的区别:
结果虽然相同,但是包含yield语句的函数会特地编译成生成器,当函数被调用的时候,他们返回一个生成器对象,这个对象支持迭代器接口,
每当遇到yield关键字的时候,可以理解成函数的return语句,yield后面的值,就是返回值。但是不像一般函数在return后退出,生成器函数在生成
值后会自动挂起并暂停他们的执行和状态,他的本地变量将保存状态信息,这些信息在函数恢复时将再度有效,下次从yield下面的部分开始执行。
比如说上一次执行到3,下次开始时,找到3的位置,从6开始执行,(不会从头开始执行),以此类推。
补充学习:http://www.jianshu.com/p/d09778f4e055
生成式:一次性生成所有数据,然后保存在内存中,适合小量的数据。
生成器:返回一个可迭代的对象,即"generator"对象,必须通过循环才可以一一列出所有结果。
2. 迭代器
iterable (可迭代对象) 和 iterator(迭代器)主要区别:
凡是可以用 for 循环的都是iterable(可迭代对象),可以通过循环调用出来的都是,比如:[],(),{},生成式....
凡是要通过 next()函数调用并获得值的可迭代对象都是iterator(迭代器)
所以生成器可以被next()函数调用并不断返回下一个值的对象称为迭代器
可以简单理解为 生成器 就是迭代器的可迭代对象。
凡是可作用于 for 循环的对象都是iterable 类
凡是可作用于 next()函数的对象都是iterator类型,他们表示一个惰性计算的序列。
作业:
九九乘法表
def func(n):
return ["{0}*{1}={2}".format(x,n,x*n) for x in xrange(1,n+1) ]
for i in xrange(1,10):
print " ".join(func(i))