
上次推文我們介紹了python中的Logging日志模塊的相關(guān)知識(shí)——Python實(shí)用教程系列——Logging日志模塊,這次推文我們將學(xué)習(xí)一下python中的高階函數(shù)等相關(guān)的知識(shí),這些高階函數(shù)我們是非常常見的,比如我們經(jīng)常使用的Map、Filter、Reduce。
一、定義
在學(xué)習(xí)python的基礎(chǔ)知識(shí)的時(shí)候,我們可能會(huì)學(xué)到一個(gè)概念“函數(shù)式編程”,我們來看看百度百科的介紹:
"函數(shù)式編程"是一種"編程范式"(programming paradigm),也就是如何編寫程序的方法論。它屬于"結(jié)構(gòu)化編程"的一種,主要思想是把運(yùn)算過程盡量寫成一系列嵌套的函數(shù)調(diào)用。
也就是說函數(shù)式編程有這樣的特點(diǎn):
- 函數(shù)可作為對(duì)象可以賦值給變量。
- 函數(shù)可作為參數(shù)傳遞給另一個(gè)函數(shù)。
- 函數(shù)可作為一個(gè)參數(shù)返回。
那么高階函數(shù)的定義是什么呢?簡(jiǎn)單的來說,只要滿足一下的條件就可以認(rèn)為這個(gè)函數(shù)是高階函數(shù):
- 函數(shù)可以作為參數(shù)傳給另外一個(gè)函數(shù);
- 函數(shù)的返回值為另外一個(gè)函數(shù);
當(dāng)然了,若一個(gè)函數(shù)的返回值為該函數(shù)本身的話,很顯然就這就是我們常見的遞歸。
我們來看看幾個(gè)簡(jiǎn)單的例子:
# 例1 函數(shù)作為參數(shù)傳給另外一個(gè)函數(shù)
def print_1():
print("打印1")
def print_2(print_1):
# 調(diào)用print_1()函數(shù)
print_1()
print("打印2")
print("打印結(jié)束")
# 函數(shù)調(diào)用,參數(shù)為print_1()函數(shù)
print_2(print_1)
#例2
#返回值為一個(gè)函數(shù)
def print_1():
print("我愛python")
def print_2():
print("我愛python知識(shí)學(xué)堂")
# 返回值為一個(gè)函數(shù)
return(print_1())
# 函數(shù)調(diào)用
print_2()
二、Map
Map()是python內(nèi)置函數(shù),它會(huì)根據(jù)所傳遞的函數(shù)對(duì)指定的序列(可迭代)做映射,原型如下:
map(func, *iterables) --> map object
參數(shù)function:是一個(gè)函數(shù),是自定義或者python內(nèi)置的函數(shù)都可以。
參數(shù)*****iterable:是可迭代的對(duì)象,比如我們常用的列表,元組等。
返回值map object:表示map函數(shù)的返回值是一個(gè)map對(duì)象。
簡(jiǎn)單的來說這個(gè)Map函數(shù)的功能就是使用func對(duì)傳入的iterable的每一個(gè)元素(比如列表的每一個(gè)元素)進(jìn)行處理,返回對(duì)象如
<map object at 0x00000272BB702128>
注意到參數(shù)iterable是加了符號(hào)“*”的,所以說這個(gè)參數(shù)的意思是可以接受多個(gè)可迭代的對(duì)象的。接下來我們看幾個(gè)例子:
1、Function為內(nèi)置函數(shù)
string_1 = 'Python知識(shí)學(xué)堂' #字符串
string_2 = [1,2,3,4,5,6] #列表
string_3 = {'python':2,'學(xué)習(xí)':3,1:4} #字典
res1 = map(str,string_1)
res2 = map(str,string_2)
res3 = map(str,string_3)
print(string_1)
print(list(res1))
print(list(res2))
print(list(res3))
上述例子使用python的內(nèi)置函數(shù)str()將字符串和列表的每個(gè)元素變成了str類型,根據(jù)map函數(shù)的說明我們知道res1和res2是一個(gè)Iterator,Iterator是惰性可迭代序列,因此通過list()函數(shù)將值求出來,注意,map不改變?cè)璴ist。
關(guān)于迭代器的惰性計(jì)算,這里先引用網(wǎng)上的一句話:
“迭代器的一個(gè)優(yōu)點(diǎn)就是它不要求你事先準(zhǔn)備好整個(gè)迭代過程中所有的元素。迭代器僅僅在迭代至某個(gè)元素時(shí)才計(jì)算該元素,而在這之前或之后,元素可以不存在或者被銷毀。這個(gè)特點(diǎn)使得它特別適合用于遍歷一些巨大的或是無限的集合,比如幾個(gè)G的文件,或是斐波那契數(shù)列等等。這個(gè)特點(diǎn)被稱為延遲計(jì)算或惰性求值(Lazy evaluation)?!?/strong>
2、Function為自定義函數(shù)
上述使用的是python的內(nèi)置函數(shù)str(),實(shí)際的項(xiàng)目中我們更多的是傳入自定義的函數(shù):
def self_test(x):
return x + 2
string = [1,2,3,4,5,6]
res = map(self_test, string)
print(list(res))
#輸出 [3, 4, 5, 6, 7, 8]
上述代碼中 向map函數(shù)中傳入了自定義的self_test函數(shù),函數(shù)加對(duì)傳入的元素加2的處理,理解起來還是很簡(jiǎn)單的。
3、多個(gè)Iterable
之前說過,參數(shù)*iterable可以是多個(gè)可迭代對(duì)象的,我們來一探究竟:
def func(x,y,z):
return x**2, y**2, z**2
List1 = [1, 2]
List2 = [1, 2, 3, 4]
List3 = [1, 2, 3, 4, 5]
res = map(func, List1, List2, List3)
print(list(res))
#輸出 [(1, 1, 1), (4, 4, 4)]
可以看出,map()函數(shù)中傳入了多個(gè)iterable。輸出的結(jié)果中列表的長度為2。這是為什么?很簡(jiǎn)單,這里有一個(gè)知識(shí)點(diǎn):輸出的list的長度取決于*iterable中傳入的litrable的最小長度,比如在上述中List1、List2和List3中最短的為List1,長度為2。
4、For循環(huán)取內(nèi)容
我們知道,map()函數(shù)的返回為一個(gè)map對(duì)象,如:
<map object at 0x00000272BB702128>
我們之前的操作是使用list輸出里面的內(nèi)容的,實(shí)際上我們也可以使用for循環(huán)遍歷的方式取值:
#for循環(huán)來取出內(nèi)容
def add_test(x):
return x + 2
string = [1,2,3,4,5,6]
res = map(add_test, string)
res_ls=[]
for i in res:
res_ls.append(i)
print(res_ls)
輸出的結(jié)果跟上述一樣,就不多分析了,有的小伙伴學(xué)習(xí)到這,就在想我們自己該怎么實(shí)現(xiàn)?
map()函數(shù)的功能呢?其實(shí)也不太難,我們接著看。
5、自實(shí)現(xiàn)Map()功能
def add_test(x):
return x + 2
# 實(shí)現(xiàn)map()函數(shù)功能
def self_map(function,iterable):
str_1=[]
for each in iterable:
each_num = function(each)
str_1.append(each_num)
return str_1.__iter__()
string = [1,2,3,4,5,6]
result = self_map(add_test,string)
print(list(result))
上述代碼的輸出為:[3, 4, 5, 6, 7, 8],且完成了map函數(shù)的功能了。小伙伴們可能對(duì)代碼代碼str_1.iter()比較好奇,這個(gè)代碼的功能就是將str_1轉(zhuǎn)換為迭代器對(duì)象。
map()函數(shù)我們就介紹到這,接下來來看另一個(gè)高階函數(shù)filter()。
三、Filter
看到這個(gè)函數(shù)的名字大家就知道其功能大概就是來過濾一些什么的,那具體是怎樣的呢?
filter()是python內(nèi)置函數(shù),它會(huì)根據(jù)所傳遞的函數(shù)對(duì)指定的對(duì)象(可迭代)做過濾,原型如下:
filter(function or None, iterable) --> filter object
可以看出該函數(shù)接收兩個(gè)參數(shù),第一個(gè)為函數(shù),第二個(gè)為可迭代對(duì)象,序列的每個(gè)元素作為參數(shù)傳遞給函數(shù)進(jìn)行判斷,然后返回 True 或 False,最后將返回 True 的元素放到新列表(或迭代器)中。
1、Filter()實(shí)例
我們來看實(shí)例,注意filter()函數(shù)的返回時(shí)filter可迭代的對(duì)象,如:
<filter object at 0x0000023D19128E48>,所以在輸出的時(shí)候需要使用list()函數(shù)轉(zhuǎn)換一下,當(dāng)然了也可以使用for循環(huán)來取值。
def select_element(string):
if 'p' in string:
return True
# return 1
else:
return False
# return 0
res_1 = filter(select_element, ['1','2','3','python'])
res_2 = filter(select_element, {'python':1,'知識(shí)':2,'學(xué)堂':3})
print(list(res_1))
print(list(res_2))
# 輸出均為
# ['python']
# ['python']
2、自實(shí)現(xiàn)Filter()功能
跟map()一樣,我們自己來實(shí)現(xiàn)filter()的功能:
# 自實(shí)現(xiàn)filte()函數(shù)功能
def select_element(string):
if 'p' in string:
return True
# return 1
else:
return False
# return 0
def filter_test(function,iterable):
str_1=[]
for each in iterable:
if function(each):
str_1.append(each)
return str_1
string = ['1','2','3','python']
res1 = filter_test(select_element,string)
res2 = filter_test(lambda x:x=='python',string)
print(res1)
print(res2)
輸出結(jié)果跟之前的一樣,其中
res2 = filter_test(lambda x:x=='python',string)中使用了lambda函數(shù),我們以后再具體介紹這類函數(shù)的使用。filter()函數(shù)我們就介紹到這,接下來來看另一個(gè)高階函數(shù)reduce ()。
四、Reduce
跟map()、filter()類似,reduce()是一個(gè)以函數(shù)以及sequence為參數(shù)的高階函數(shù),其返回值為一個(gè)value值而不是迭代器對(duì)象。其原型如下:
reduce(function, sequence[, initial]) -> value
但reduce()傳入的函數(shù)必須接收兩個(gè)參數(shù),比如func (x,y)滿足條件,但是func(x,y,z)并不滿足條件。
Initial為初始化的一個(gè)參數(shù),可不填。(如果沒有指定Initial的值那么其為sequence的第一個(gè)元素的值)。
1、Reduce()實(shí)例
在看reduce()函數(shù)的實(shí)例之前,我們來看一個(gè)圖解釋一下reduce的執(zhí)行過程:

看圖很簡(jiǎn)單:reduce每一次迭代,都將上一次的迭代結(jié)果與下一個(gè)元素一起傳入function函數(shù)中,取得值以后將其與下一個(gè)元素一起繼續(xù)下傳…找到使用到sequence中的最后一個(gè)元素。
我們來看一個(gè)使用reduce()函數(shù)的實(shí)例:
# 需要functools從導(dǎo)入
from functools import reduce
def func(x, y):
return x + y
string = [1, 3, 5, 7, 9]
result_1 = reduce(func,string)
result_2 = reduce(func,string,100)
print(result_1)
print(result_2)
上述代碼輸出為:25和125,result_2使用initial = 100。
其中25的值可以這樣理解:25 = ((((1+3)+5)+7)+9)
其中125的值可以這樣理解:125 = (((((100+1)+3)+5)+57)+9)
其實(shí)上述reduce的計(jì)算過程還是比較好理解的,其實(shí)在Python中還有一個(gè)函數(shù)sum(),可以直接求職的,具體的求值語句:res = sum(string)。
2、自實(shí)現(xiàn)Reduce()功能
Reduce函數(shù)自定義實(shí)現(xiàn)也比較簡(jiǎn)單,我們來看看這個(gè)實(shí)現(xiàn)怎么寫:
def func(x, y):
return x + y
def self_reduce(function, string, initializer=None):
it = iter(string)
if initializer is None:
value = next(it)
else:
value = initializer
for each_ele in it:
value = function(value, each_ele)
return value
string = {1, 3, 5, 7, 9}
# string = [1, 3, 5, 7, 9]
result_1 = self_reduce(func,string)
result_2 = self_reduce(func,string,100)
print(result_1)
print(result_2)
輸出結(jié)果跟上述一樣,這里的string = {1, 3, 5, 7, 9}是一個(gè)集合,即傳入的是一個(gè)集合,當(dāng)然了string = [1, 3, 5, 7, 9]也是可以的。
或者使用以下的方法實(shí)現(xiàn)Reduce()方法的功能也是可以的:
def func(x, y):
return x + y
def self_reduce(function, iterable, initializer=None):
if initializer is None:
value =iterable.pop(0)
else:
value=initializer
for each_ele in iterable:
value=function(value,each_ele)
return value
string = {1, 3, 5, 7, 9}
result_1 = self_reduce(func,string,100)
print(result_1)
輸出結(jié)果為:125
五、總結(jié)
以上就是本次推文的所有內(nèi)容啦!主要講的是Python中的高階函數(shù),具體的內(nèi)容涉及到高階函數(shù)的定義和概念,具體的講解了三個(gè)常用的高階函數(shù):map,filter,reduce的使用方法,同時(shí)也講解了如何自己實(shí)現(xiàn)這三者的功能,這個(gè)自己實(shí)現(xiàn)三者功能的方法大家可以好好研究下。
在實(shí)際的工程項(xiàng)目中,運(yùn)用好這些方法,不僅會(huì)減少代碼量,而且在很大的程度上還能加速代碼的運(yùn)行速度。