先看以下这段代码:
L = []
def my_func(x):
return 2*x
for i in range(5):
L.append(my_func(i))
L
#Output:[0, 2, 4, 6, 8]
事实上可以利用列表推导式进行写法上的简化:[* for i in ]。其中,第一个为映射函数,其输入为后面i指代的内容,第二个*表示迭代的对象。
[my_func(i) for i in range(5)]
#Output:[0, 2, 4, 6, 8]
列表表达式还支持多层嵌套,如下面的例子中第一个for为外层循环,第二个为内层循环:
[m+'_'+n for m in ['a', 'b'] for n in ['c', 'd']]
#output:['a_c', 'a_d', 'b_c', 'b_d']
除了列表推导式,另一个实用的语法糖是带有if选择的条件赋值(或称三元表达式),其形式为value = a if condition else b:
value = 'cat' if 2>1 else 'dog'
value
#output:'cat'
下面举一个例子,截断列表中超过5的元素,即超过5的用5代替,小于5的保留原来的值:
L = [1, 2, 3, 4, 5, 6, 7]
[i if i <= 5 else 5 for i in L]
#output:[1, 2, 3, 4, 5, 5, 5]
有一些函数的定义具有清晰简单的映射关系,例如上面的my_func函数,这时候可以用匿名函数的方法简洁地表示:
my_func = lambda x: 2*x
my_func(3)
#output:6
multi_para_func = lambda a, b: a + b
multi_para_func(1, 2)
#output:3
但上面的用法其实违背了“匿名”的含义,事实上它往往在无需多处调用的场合进行使用,例如上面列表推导式中的例子,用户不关心函数的名字,只关心这种映射的关系:
[(lambda x: 2*x)(i) for i in range(5)]
#output:[0, 2, 4, 6, 8]
对于上述的这种列表推导式的匿名函数映射,Python中提供了map函数来完成,它返回的是一个map对象,需要通过list转为列表:
list(map(lambda x: 2*x, range(5)))
#output:[0, 2, 4, 6, 8]
对于多个输入值的函数映射,可以通过追加迭代对象实现:
list(map(lambda x, y: str(x)+'_'+y, range(5), list('abcde')))
#output:['0_a', '1_b', '2_c', '3_d', '4_e']
zip函数能够把多个可迭代对象打包成一个元组构成的可迭代对象,它返回了一个zip对象,通过tuple, list可以得到相应的打包结果:
L1, L2, L3 = list('abc'), list('def'), list('hij')
list(zip(L1, L2, L3))
#output:[('a', 'd', 'h'), ('b', 'e', 'i'), ('c', 'f', 'j')]
tuple(zip(L1, L2, L3))
#output:(('a', 'd', 'h'), ('b', 'e', 'i'), ('c', 'f', 'j'))
往往会在循环迭代的时候使用到zip函数:
for i, j, k in zip(L1, L2, L3):
print(i, j, k)
#output:
a d h
b e i
c f j
enumerate是一种特殊的打包,它可以在迭代时绑定迭代元素的遍历序号:
L = list('abcd')
for index, value in enumerate(L):
print(index, value)
#output:
0 a
1 b
2 c
3 d
当需要对两个列表建立字典映射时,可以利用zip对象:
dict(zip(L1, L2))
#output:{'a': 'd', 'b': 'e', 'c': 'f'}
既然有了压缩函数,那么Python也提供了*操作符和zip联合使用来进行解压操作:
zipped = list(zip(L1, L2, L3))
zipped
#output:[('a', 'd', 'h'), ('b', 'e', 'i'), ('c', 'f', 'j')]
list(zip(*zipped)) # 三个元组分别对应原来的列表
#output:[('a', 'b', 'c'), ('d', 'e', 'f'), ('h', 'i', 'j')]