列表生成式

  列表生成式是Python函数的高级特性,顾名思义就是用来创建列表(list)的生成式。

  基础语法: [exp for iter_var in iterable] 

  如[x * x for x in range(1, 11)] 就是一个列表生成式。首先迭代 iterable 里所有内容, 每一次迭代, 都把 iterable 里相应内容放到 iter_var 中, 再在表达式 exp 中应用该 iter_var 的内容, 最后用表达式的计算值生成一个新的列表。

print '利用range()生成一个list'
print range(1,11)
print '计算1-10各自的平方'
for i in xrange(1,11):
   print i*i,
print '\n函数形式实现1-10各自的平方'
def fuc():
   L1=[]
   for i in xrange(1,11):
       L1.append(i*i)
   return L1
print fuc()
print '\n利用列表生成式计算1-10各自的平方'
print [x*x for x in xrange(1,11)]

运行结果:
利用range()生成一个list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
计算1-10各自的平方
1 4 9 16 25 36 49 64 81 100
函数形式实现1-10各自的平方
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
利用列表生成式计算1-10各自的平方
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

  从例子中可以很直观的看出无论是用循坏还是普通函数,代码都有好几行,而使用列表生成式就一行代码实现了功能,及简化了代码又有更好的复用性。

  生成式for循环后还是使用if判断语句,如下例子:

print '1-100间的所有偶数'
L1=[a for a in xrange(1,101) if a%2==0]
print L1
print '1-100间的所有奇数'
L2=[b for b in xrange(1,101) if b%2==1]
print L2
print '1-100间所有偶数的平方'
L3=[c*c for c in xrange(1,101) if c%2==0]
print L3
print '1-100间所有奇数的平方'
L4=[d*d for d in xrange(1,101) if d%2==1]
print L4

运行结果:
1-100间的所有偶数
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
1-100间的所有奇数
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
1-100间所有偶数的平方
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784, 900, 1024, 1156, 1296, 1444, 1600, 1764, 1936, 2116, 2304, 2500, 2704, 2916, 3136, 3364, 3600, 3844, 4096, 4356, 4624, 4900, 5184, 5476, 5776, 6084, 6400, 6724, 7056, 7396, 7744, 8100, 8464, 8836, 9216, 9604, 10000]
1-100间所有奇数的平方
[1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625, 729, 841, 961, 1089, 1225, 1369, 1521, 1681, 1849, 2025, 2209, 2401, 2601, 2809, 3025, 3249, 3481, 3721, 3969, 4225, 4489, 4761, 5041, 5329, 5625, 5929, 6241, 6561, 6889, 7225, 7569, 7921, 8281, 8649, 9025, 9409, 9801]

  生成式可以使用两层循环,如下例子:格式化输出某位学生所有科目的考试成绩

dic={'chinese':98,'math':99,'pysical':89,'chemistry':80,'biology':96}
print dic.items()
L1=[a+':'+str(b) for a,b in dic.iteritems()]
print L1

运行结果:
[('pysical', 89), ('biology', 96), ('chemistry', 80), ('math', 99), ('chinese', 98)]
['pysical:89', 'biology:96', 'chemistry:80', 'math:99', 'chinese:98']

  列表生成式虽然简洁易用,但有的情形不用:当需要只是执行一个循环的时候;当有内建的操作或者类型能够以更直接的方式实现的;如果需要对每个元素都调用并且返回结果时。

生成器

  当我们调用一个普通的python函数时,一般都是从函数的第一行开始执行,直到遇到return语句或者异常或者函数的最后一行。这样,函数就将控制权交还与调用者,函数中的所有工具以及局部变量等数据都将丢失。再次调用这个函数的时候,所有的局部变量,堆栈信息都将重新创建,跟之前的调用再无关系。

  生成器(generator)其实对我们来说并不陌生,最简单的方法就是把列表的方括号改成圆括号,如下:

L1=[x for x in xrange(1,5)]
L2=(y for y in xrange(1,5))
print type(L1),L1
print type(L2),L2
print L2.next()
print L2.next()
print L2.next()
print L2.next()
print L2.next()

运行结果:
<type 'list'> [1, 2, 3, 4]
<type 'generator'> <generator object <genexpr> at 0x0000000004F2D480>
1
2
3
4
Traceback (most recent call last):
<type 'generator'> <generator object <genexpr> at 0x00000000055BD480>
 File "C:/Users/YangQing/PycharmProjects/Test/Iterator.py", line 44, in <module>
   L2.next()
StopIteration

  有时候我们并不希望函数只返回一个值,而是希望返回一个序列。要做到这一点,这种函数需要能够保存自己的工作状态。这样的话,就不能使用我们通常所使用的return语句,因为一旦使用return语句,代码执行的控制权就交给了函数被调用的地方,函数的所有状态将被清零。在这种情况下,我们就需要使用yield关键字。含有yield关键字的地方,就是一个生成器(generator)

print '普通函数'
def sn(n):
   ss=[]
   for i in xrange(n):
       ss.append(i*i)
   return ss
for b in sn(5):
   print b,
print '\n生成器'
def sm(m):
   for i in xrange(m):
       yield i*i
for a in sm(5):
   print a,
   
运行结果:
普通函数
0 1 4 9 16
生成器
0 1 4 9 16

  在python中,生成器通过生成器函数生成,生成器函数定义的方法跟普通函数定义的方法一致。唯一不同的地方是,生成器函数不用return返回,而是用yield关键字一次返回一个结果,在每个结果之间挂起与继续他们的状态,来自动实现迭代(循环)。 

(1)当调用生成器函数时候,函数返回的,只是一个生成器对象,并没有真正执行里面的逻辑; 
(2)当next()方法第一次被调用以后,生成器才真正开始工作。一旦遇到yield语句,代码便停止运行。注意此时的停止运行跟return的是不一样的;
(3)调用next()方法的时候,返回的是yield处的参数值;
(4)当继续调用next()方法时,代码将在上一次停止的yield语句处继续执行,并且到下一个yield处停止; 
(5)一直到后面没有yield语句,最后抛出StopIteration的异常;

迭代器

  在Python中,如果给定一个列表(list)或元组(tuple),我们可以通过for循环来遍历这个列表(list)或元组(tuple),这种遍历我们成为迭代(Iteration)。在Python中,迭代是通过 for ... in 来完成的。只要是实现了__iter__()方法的对象,就可以使用迭代器进行访问。

  迭代操作就是对于一个集合,无论该集合是有序还是无序,我们用 for 循环总是可以依次取出集合的每一个元素。这类集合称作可迭代对象,字典就是典型的可迭代对象,下面举例:

dic={'Name':'John','Hob':'Music','Code':'0590','Address':'Fuzhou'}
print dir(dic)
print dic.items()
for a in dic.iteritems():
   print a
for b in dic.iterkeys():
   print b
for c in dic.itervalues():
   print c
 
运行结果:
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']
[('Code', '0590'), ('Hob', 'Music'), ('Name', 'John'), ('Address', 'Fuzhou')]
('Code', '0590')
('Hob', 'Music')
('Name', 'John')
('Address', 'Fuzhou')
Code
Hob
Name
Address
0590
Music
John
Fuzhou

装饰器

  装饰器(Decorator)其实就是一个以函数作为参数并返回一个替换函数的可执行函数。

>>> def outer(func1):
...     def inner():
...         print "before func1"
...         ret = func1() # 1
...         return ret + 1
...     return inner
>>> def foo():
...     return 1
>>> decorated = outer(foo) # 2
>>> decorated()
before func1    

  首先,定义了一个带单个参数func1的名为outer的函数。然后在outer内部定义了一个内嵌函数inner。inner函数将打印一行字符串然后调用func1,并在#1处获取其返回值。在每次outer被调用时,func1的值可能都会不同,但不论func1是什么函数,都将调用它。最后,inner返回func1()的返回值加1。在#2 处可以看到,当调用赋值给decorated的返回函数时,得到的是一行文本输出和返回值2,而非期望的调用foo的返回值1。

练习:利用函数实现九九乘法表:

print '常规方法一:for循环'
for i in xrange(1,10):
   for j in xrange(1,i+1):
       print j,"x",i,"=",j*i,"",
       # print '{} x {} = {}\t'.format(i, j, i * j),
       # print '%d x %d = %d\t'%(i,j,i*j),
       if j>=i:
            print('')
print '常规方法二:while循坏'
i=0
j=0
while i<9:
   i+=1
   while j<9:
       j+=1
       # print j,"x",i,"=",j*i,"",
       print '{} x {} = {}\t'.format(i, j, i * j),
       # print '%d x %d = %d\t'%(i,j,i*j),
       if i==j:
           j=0
           print('')
           break
print '函数方法'
def nn():
   for i in xrange(1, 10):
       for j in xrange(1, i + 1):
           # print j,"x",i,"=",j*i,"",
           # print '{} x {} = {}\t'.format(i, j, i * j),
           print '%d x %d = %d\t'%(i,j,i*j),
           if j >= i:
               print('')
   return
nn()

运行结果:
常规方法一:for循环
1 x 1 = 1  
1 x 2 = 2  2 x 2 = 4  
1 x 3 = 3  2 x 3 = 6  3 x 3 = 9  
1 x 4 = 4  2 x 4 = 8  3 x 4 = 12  4 x 4 = 16  
1 x 5 = 5  2 x 5 = 10  3 x 5 = 15  4 x 5 = 20  5 x 5 = 25  
1 x 6 = 6  2 x 6 = 12  3 x 6 = 18  4 x 6 = 24  5 x 6 = 30  6 x 6 = 36  
1 x 7 = 7  2 x 7 = 14  3 x 7 = 21  4 x 7 = 28  5 x 7 = 35  6 x 7 = 42  7 x 7 = 49  
1 x 8 = 8  2 x 8 = 16  3 x 8 = 24  4 x 8 = 32  5 x 8 = 40  6 x 8 = 48  7 x 8 = 56  8 x 8 = 64  
1 x 9 = 9  2 x 9 = 18  3 x 9 = 27  4 x 9 = 36  5 x 9 = 45  6 x 9 = 54  7 x 9 = 63  8 x 9 = 72  9 x 9 = 81  
常规方法二:while循坏
1 x 1 = 1  
1 x 2 = 2  2 x 2 = 4  
1 x 3 = 3  2 x 3 = 6  3 x 3 = 9  
1 x 4 = 4  2 x 4 = 8  3 x 4 = 12  4 x 4 = 16  
1 x 5 = 5  2 x 5 = 10  3 x 5 = 15  4 x 5 = 20  5 x 5 = 25  
1 x 6 = 6  2 x 6 = 12  3 x 6 = 18  4 x 6 = 24  5 x 6 = 30  6 x 6 = 36  
1 x 7 = 7  2 x 7 = 14  3 x 7 = 21  4 x 7 = 28  5 x 7 = 35  6 x 7 = 42  7 x 7 = 49  
1 x 8 = 8  2 x 8 = 16  3 x 8 = 24  4 x 8 = 32  5 x 8 = 40  6 x 8 = 48  7 x 8 = 56  8 x 8 = 64  
1 x 9 = 9  2 x 9 = 18  3 x 9 = 27  4 x 9 = 36  5 x 9 = 45  6 x 9 = 54  7 x 9 = 63  8 x 9 = 72  9 x 9 = 81
函数方法
1 x 1 = 1  
1 x 2 = 2  2 x 2 = 4  
1 x 3 = 3  2 x 3 = 6  3 x 3 = 9  
1 x 4 = 4  2 x 4 = 8  3 x 4 = 12  4 x 4 = 16  
1 x 5 = 5  2 x 5 = 10  3 x 5 = 15  4 x 5 = 20  5 x 5 = 25  
1 x 6 = 6  2 x 6 = 12  3 x 6 = 18  4 x 6 = 24  5 x 6 = 30  6 x 6 = 36  
1 x 7 = 7  2 x 7 = 14  3 x 7 = 21  4 x 7 = 28  5 x 7 = 35  6 x 7 = 42  7 x 7 = 49  
1 x 8 = 8  2 x 8 = 16  3 x 8 = 24  4 x 8 = 32  5 x 8 = 40  6 x 8 = 48  7 x 8 = 56  8 x 8 = 64  
1 x 9 = 9  2 x 9 = 18  3 x 9 = 27  4 x 9 = 36  5 x 9 = 45  6 x 9 = 54  7 x 9 = 63  8 x 9 = 72  9 x 9 = 81