1
+ > Ever since the creation of the world his eternal power dan divine nature, invisible though they are , have been understood and seen through the things ha has made. So they are without excuse; for they knew God, they did not honor him as God or give thanks to him, but they became futile in their thinking, and their senseless minds were darkened. Claiming to be wise, they became fools; and they exchange the glory of the immorrtal God for images resembling a mortal human being or birds or four-footed animals or reptiles. (ROMANS 1:20-23)
2
+
3
+ #函数(5)
4
+
1
5
##几个特殊函数
2
6
3
- 前面已经知道了如何编写、调用函数。此外, 在python中,有几个特别的函数,很有意思,它们常常被看做是python能够进行所谓 “函数式编程”的见证。
7
+ 在python中,有几个特别的函数,它们常常被看做是Python能够进行所谓 “函数式编程”的见证,虽然我认为Python不可能走上那条发展道路 。
4
8
5
9
> 如果以前没有听过,等你开始进入编程界,也会经常听人说“函数式编程”、“面向对象编程”、“指令式编程”等属于。它们是什么呢?这个话题要从“编程范式”讲起。(以下内容源自维基百科)
6
10
14
18
15
19
不管读者是初学还是老油条,都建议将上面这段话认真读完,不管理解还是不理解,总能有点感觉的。
16
20
17
- 正如前面引文中所说的,python是支持多种范型的语言 ,可以进行所谓函数式编程,其突出体现在有这么几个函数:
21
+ 正如前面引文中所说的,Python是支持多种范型的语言 ,可以进行所谓函数式编程,其突出体现在有这么几个函数:filter、map、reduce、lambda、yield。
18
22
19
- filter、map、reduce、lambda、yield
23
+ 有了它们,最大的好处是程序更简洁;没有它们,程序也可以用别的方式实现,也不一定麻烦,或者相差无几。
20
24
21
- 有了它们,最大的好处是程序更简洁;没有它们,程序也可以用别的方式实现,只不过麻烦一些罢了。所以,还是能用则用之吧。更何况,恰当地使用这几个函数 ,能让别人感觉你更牛X。
25
+ 因此,在编程实践中,可以不用这些特殊函数,但本着艺不压身的想法,还是要介绍,并且恰当地使用这几个函数 ,能让别人感觉你更牛X。
22
26
23
27
(注:本节不对yield进行介绍,请阅读[ 《生成器》] ( ./215.md ) )
24
28
25
- ##lambda
29
+ ### lambda
26
30
27
31
lambda函数,是一个只用一行就能解决问题的函数,听着是多么诱人呀。看下面的例子:
28
32
29
- >>> def add(x): #定义一个函数,将输入的变量增加3,然后返回增加之后的值
33
+ >>> def add(x):
30
34
... x += 3
31
35
... return x
32
36
...
33
37
>>> numbers = range(10)
34
38
>>> numbers
35
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #有这样一个list,想让每个数字增加3,然后输出到一个新的list中
39
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
36
40
37
41
>>> new_numbers = []
38
42
>>> for i in numbers:
39
- ... new_numbers.append(add(i)) #调用add()函数,并append到list中
43
+ ... new_numbers.append(add(i))
40
44
...
41
45
>>> new_numbers
42
46
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
@@ -49,7 +53,7 @@ lambda函数,是一个只用一行就能解决问题的函数,听着是多
49
53
50
54
首先说明,这种列表解析的方式是非常非常好的。
51
55
52
- 但是,我们偏偏要用lambda这个函数替代add (x),如果看官和我一样这么偏执,就可以:
56
+ 但是,我们偏偏要用lambda这个函数替代 ` add (x)` 。
53
57
54
58
>>> lam = lambda x:x+3
55
59
>>> n2 = []
@@ -59,12 +63,12 @@ lambda函数,是一个只用一行就能解决问题的函数,听着是多
59
63
>>> n2
60
64
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
61
65
62
- 这里的lam就相当于add (x),请看官对应一下,这一行lambda x: x +3就完成add (x)的三行(还是两行?),特别是最后返回值 。还可以写这样的例子:
66
+ 这里的 ` lam ` 就相当于 ` add (x)` ,这一行 ` lambda x:x+3 ` 就完成 ` add (x)` 函数体里面的两行 。还可以写这样的例子:
63
67
64
- >>> g = lambda x,y:x+ y #x+y,并返回结果
65
- >>> g(3,4)
68
+ >>> g = lambda x, y: x + y
69
+ >>> g(3, 4)
66
70
7
67
- >>> (lambda x:x** 2)(4) #返回4的平方
71
+ >>> (lambda x : x ** 2)(4) #返回4的平方
68
72
16
69
73
70
74
通过上面例子,总结一下lambda函数的使用方法:
@@ -77,11 +81,11 @@ lambda函数,是一个只用一行就能解决问题的函数,听着是多
77
81
78
82
lambda arg1, arg2, ...argN : expression using arguments
79
83
80
- 要特别提醒看官 :虽然lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值,但是** lambda 函数不能包含命令,包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。**
84
+ 要特别提醒 :虽然lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值,但是** lambda 函数不能包含命令,包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。**
81
85
82
- 就lambda而言,它并没有给程序带来性能上的提升,它带来的是代码的简洁。比如,要打印一个list ,里面依次是某个数字的1次方,二次方,三次方,四次方。用lambda可以这样做:
86
+ 就lambda而言,它并没有给程序带来性能上的提升,它带来的是代码的简洁。比如,要打印一列表 ,里面依次是某个数字的1次方,二次方,三次方,四次方。用lambda可以这样做:
83
87
84
- >>> lamb = [ lambda x:x,lambda x:x**2,lambda x:x**3,lambda x:x**4 ]
88
+ >>> lamb = [ lambda x:x, lambda x:x**2, lambda x:x**3, lambda x:x**4 ]
85
89
>>> for i in lamb:
86
90
... print i(3),
87
91
...
@@ -93,20 +97,17 @@ lambda做为一个单行的函数,在编程实践中,可以选择使用。
93
97
94
98
先看一个例子,还是上面讲述lambda的时候第一个例子,用map也能够实现:
95
99
96
- >>> numbers
97
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #把列表中每一项都加3
100
+ >>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
98
101
99
- >>> map(add,numbers) #add(x)是上面讲述的那个函数,但是这里只引用函数名称即可
102
+ >>> map(add, numbers)
100
103
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
101
104
102
- >>> map(lambda x: x+3,numbers) #用lambda当然可以啦
105
+ >>> map(lambda x: x+3, numbers) #用lambda当然可以啦
103
106
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
104
107
105
- map()是python的一个内置函数,它的基本样式是:
108
+ map()是python的一个内置函数,它的基本样式是` map(func,seq) ` 。
106
109
107
- ` map(func,seq) `
108
-
109
- func是一个函数,seq是一个序列对象。在执行的时候,序列对象中的每个元素,按照从左到右的顺序,依次被取出来,并塞入到func那个函数里面,并将func的返回值依次存到一个list中。
110
+ func是一个函数,seq是一个序列对象。在执行的时候,序列对象中的每个元素,按照从左到右的顺序,依次被取出来,塞入到func那个函数里面,并将func的返回值依次存到一个列表中。
110
111
111
112
在应用中,map的所能实现的,也可以用别的方式实现。比如:
112
113
@@ -139,35 +140,37 @@ func是一个函数,seq是一个序列对象。在执行的时候,序列对
139
140
140
141
理解要点:
141
142
142
- - 对iterable中的每个元素 ,依次应用function的方法(函数)(这本质上就是一个for循环)。
143
- - 将所有结果返回一个list 。
143
+ - 对可迭代对象中的每个元素 ,依次应用function的方法(函数)(这本质上就是一个for循环)。
144
+ - 将所有结果返回一个列表 。
144
145
- 如果参数很多,则对那些参数并行执行function。
145
146
146
147
例如:
147
148
148
- >>> lst1 = [1,2,3,4, 5]
149
- >>> lst2 = [6,7,8,9, 0]
150
- >>> map(lambda x,y: x+ y, lst1,lst2) #将两个列表中的对应项加起来,并返回一个结果列表
149
+ >>> lst1 = [1, 2, 3, 4, 5]
150
+ >>> lst2 = [6, 7, 8, 9, 0]
151
+ >>> map(lambda x, y: x + y, lst1, lst2) #将两个列表中的对应项加起来,并返回一个结果列表
151
152
[7, 9, 11, 13, 5]
152
153
153
- 请看官注意了, 上面这个例子如果用for循环来写,还不是很难,如果扩展一下,下面的例子用for来改写,就要小心了:
154
+ 上面这个例子如果用for循环来写,还不是很难,如果扩展一下,下面的例子用for来改写,就要小心了:
154
155
155
- >>> lst1 = [1,2,3,4, 5]
156
- >>> lst2 = [6,7,8,9, 0]
157
- >>> lst3 = [7,8,9,2, 1]
158
- >>> map(lambda x,y,z: x+y+z, lst1,lst2,lst3)
156
+ >>> lst1 = [1, 2, 3, 4, 5]
157
+ >>> lst2 = [6, 7, 8, 9, 0]
158
+ >>> lst3 = [7, 8, 9, 2, 1]
159
+ >>> map(lambda x,y,z: x+y+z, lst1, lst2, lst3)
159
160
[14, 17, 20, 15, 6]
160
161
161
162
这才显示出map的简洁优雅。
162
163
163
164
##reduce
164
165
165
- 直接看这个:
166
+ 首先声明:如果读者使用的是Python3,跟上面有点不一样,因为在Python3中,` reduce() ` 已经从全局命名空间中移除,放到了functools模块中,如果要是用,需要用` from functools import reduce ` 引入之。
167
+
168
+ 再看这个:
166
169
167
- >>> reduce(lambda x,y: x+y,[1,2,3,4, 5])
170
+ >>> reduce(lambda x,y: x+y,[1, 2, 3, 4, 5])
168
171
15
169
172
170
- 请看官仔细观察 ,是否能够看出是如何运算的呢?画一个图:
173
+ 请仔细观察 ,是否能够看出是如何运算的呢?画一个图:
171
174
172
175
![ ] ( ./2images/20401.png )
173
176
@@ -178,7 +181,7 @@ func是一个函数,seq是一个序列对象。在执行的时候,序列对
178
181
>>> map(lambda x,y: x+y, list1,list2)
179
182
[10, 10, 10, 10, 10, 10, 10, 10, 10]
180
183
181
- 看官对比一下 ,就知道两个的区别了。原来map是上下运算,reduce是横着逐个元素进行运算。
184
+ 对比一下 ,就知道两个的区别了。原来map是上下运算,reduce是横着逐个元素进行运算。
182
185
183
186
权威的解释来自官网:
184
187
@@ -212,22 +215,20 @@ func是一个函数,seq是一个序列对象。在执行的时候,序列对
212
215
213
216
for普世的,reduce是简洁的。
214
217
215
- 为了锻炼思维,看这么一个问题,有两个list,a = [ 3,9,8,5,2] , b=[ 1,4,9,2,6] , 计算:a[ 0] * b[ 0] +a[ 1] * b[ 1] +...的结果。
218
+ 为了锻炼思维,看这么一个问题,有两个list,` a = [3,9,8,5,2] ` , ` b=[1,4,9,2,6] ` , 计算:a[ 0] * b[ 0] +a[ 1] * b[ 1] +...的结果。
216
219
217
- >>> a
218
- [3, 9, 8, 5, 2]
219
- >>> b
220
- [1, 4, 9, 2, 6]
220
+ >>> a = [3, 9, 8, 5, 2]
221
+ >>> b = [1, 4, 9, 2, 6]
221
222
222
223
>>> zip(a,b) #复习一下zip,下面的方法中要用到
223
224
[(3, 1), (9, 4), (8, 9), (5, 2), (2, 6)]
224
225
225
226
>>> sum(x*y for x,y in zip(a,b)) #解析后直接求和
226
227
133
227
228
228
- >>> new_list = [x*y for x,y in zip(a,b)] #可以看做是上面方法的分布实施
229
+ >>> new_list = [x*y for x,y in zip(a,b)]
229
230
230
- >>> #这样解析也可以 :new_tuple = (x*y for x,y in zip(a,b))
231
+ >>> #这样也可以 :new_tuple = (x*y for x,y in zip(a,b)),与上面的区别,后续会讲到
231
232
>>> new_list
232
233
[3, 36, 72, 10, 12]
233
234
>>> sum(new_list) #或者:sum(new_tuple)
@@ -236,18 +237,20 @@ for普世的,reduce是简洁的。
236
237
>>> reduce(lambda sum,(x,y): sum+x*y,zip(a,b),0) #这个方法是在耍酷呢吗?
237
238
133
238
239
239
- >>> from operator import add,mul #耍酷的方法也不止一个
240
- >>> reduce(add,map(mul,a, b))
240
+ >>> from operator import add, mul #耍酷的方法也不止一个
241
+ >>> reduce(add, map(mul, a, b))
241
242
133
242
243
243
244
>>> reduce(lambda x,y: x+y, map(lambda x,y: x*y, a,b)) #map,reduce,lambda都齐全了,更酷吗?
244
245
133
245
246
246
- 最后,要特别提醒:如果读者使用的是python3,跟上面有点不一样,因为在python3中,reduce()已经从全局命名空间中移除,放到了functools模块中,如果要是用,需要用 ` from functools import reduce ` 引入之 。
247
+ 在Python 2中,如果使用map/reduce之类,可能或遇到性能不稳定的情况,如果是Python 3,就放心多了,不仅性能稳定,而且速度足够快 。
247
248
249
+ 但是,我还是更推荐使用列表解析,因为它可读性更好,你无法保证队友都跟你一样。
250
+
248
251
##filter
249
252
250
- filter的中文含义是“过滤器”,在python中 ,它就是起到了过滤器的作用。首先看官方说明:
253
+ filter的中文含义是“过滤器”,在Python中 ,它就是起到了过滤器的作用。首先看官方说明:
251
254
252
255
> filter(function, iterable)
253
256
@@ -273,3 +276,11 @@ filter的中文含义是“过滤器”,在python中,它就是起到了过
273
276
'qwsr' #“If iterable is a string or a tuple, the result also has that type;”
274
277
275
278
至此,介绍了几个函数,这些函数在对程序的性能提高上,并没有显著或者稳定预期,但是,在代码的简洁上,是有目共睹的。有时候是可以用来秀一秀,彰显python的优雅和自己耍酷。如何用、怎么用,看你自己的喜好了。
279
+
280
+ 不过,编程的时候,往往不能靠单纯自己的喜好,还得考虑队友。
281
+
282
+ ------
283
+
284
+ [ 总目录] ( ./index.md )   ;  ;  ; |  ;  ;  ; [ 上节:函数(4)] ( ./204.md )   ;  ;  ; |  ;  ;  ; [ 下节:函数练习] ( ./205.md )
285
+
286
+ 如果你认为有必要打赏我,请通过支付宝:
** [email protected] ** ,不胜感激。
0 commit comments