Python實(shí)用教程系列——高階函數(shù)Map、Filter、Reduce

上次推文我們介紹了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í)行過程:

image.png

看圖很簡(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)行速度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容