Python 進階之路 (六) 九淺一深 lambda,陳獨秀你給我坐下!

lambda是什麼

大家好,今天給大家帶來的是有關於Python裏面的lambda表達式詳細解析。lambda在Python裏面的用處很廣,但說實話,我個人認爲有關於lambda的討論不是如何使用的問題,而是該不該用的問題。接下來還是通過大量實例和大家分享我的學習體驗,可能最後你也會得出和我一樣的結論。

好啦,首先讓我們先搞明白基礎定義,lambda到底是什麼?

Lambda表達了Python中用於創建匿名函數的特殊語法。我們將lambda語法本身稱爲lambda表達式,從這裏得到的函數稱之爲lambda函數。

其實總結起來,lambda可以理解爲一個小的匿名函數,lambda函數可以使用任意數量的參數,但只能有一個表達式。估計有JavaScript ES6經驗的朋友們聽上去會很親切,具體函數表達式如下:

  • 模板: lambda argument: manipulate(argument)
  • 參數:argument就是這個匿名函數傳入的參數,冒號後面是我們對這個參數的操作方法

讓我們參考上面的定義模板和參數, 直接看一個最簡單的例子:

add_one = lambda x:x+1       # 1個參數,執行操作爲+1
add_nums = lambda x,y:x+y    # 2個參數,執行操作爲相加

print(add_one(2))            # 調用add_one
print(add_nums(3,7))         # 調用add_nums

>>>   3 
     10

相比大家已經發現lambda匿名函數的特點了,就是對於較爲簡單的功能,無需自己def一個了,單行就可以寫下,傳參和執行方法一氣呵成

lambda用法詳解

接下來讓我們看看lambda的實際應用,就我自己使用lambda的體驗來說,從來沒有單獨用過,lambda一般情況下是和map,filter,reduce這些超棒的內置函數以及dict,list,tuple,set 等數據結構混用,這樣才能發揮它的最大效果,如果有朋友還不太熟悉這些內置函數,可以看一下我上一篇文章 Python 進階之路 (五) map, filter, reduce, zip 一網打盡

好了,閒話少說,下面讓我們一個個來看

lambda + map

首先出場的是lambda+map的組合,先看下面這個例子:

numbers = [1,2,3,4,5]
add_one = list(map(lambda n:n+1,numbers))  #map(fun,sequence)

print(list(add_one))
print(tuple(add_one))

Out: [2, 3, 4, 5, 6]
     (2, 3, 4, 5, 6)

這個是我們上一期的例子,實現一個數組(元組)每個元素+1,讓我們回憶一下map的用法
map(fun,sequence),fun是傳遞的方法,sequence是一個可迭代的序列,這裏我們的fun就是匿名函數
lambda n:n+1,這裏非常完美的解釋了lambda的設計初衷,因爲如果沒有lambda,我們的解決方案是這樣:

def add(num):
    return num+1

numbers = [1,2,3,4,5]
add_one = list(map(add,numbers))
print(add_one)
print(tuple(add_one))

顯然易見,這裏的add方法有點多餘,所以用lambda代替是個好的選擇。讓我們再看下一個例子,這是我自己備份日誌時寫的一小段代碼,命名不是很規範:

from datetime import datetime as dt
logs = ['serverLog','appLog','paymentLog']
format ='_{}.py'.format(dt.now().strftime('%d-%m-%y'))
result =list(map(lambda x:x+format,logs))   # 利用map+lambda 實現字符串拼接
print(result)

Out:['serverLog_11-02-19.py', 'appLog_11-02-19.py', 'paymentLog_11-02-19.py']

這裏和剛纔的加1例子差不多,但是換成了字符串的拼接,然而我這裏用lambda並不是很好的解決方案,最後我們會說,現在大家應該對map + lambda 有一些感覺了,讓我們再來個和dict字典互動的例子:

person =[{'name':'Lilei',
          'city':'beijing'},
         {'name':'HanMeiMei',
          'city':'shanghai'}]

names=list(map(lambda x:x['name'],person))
print(names)

Out:['Lilei', 'HanMeiMei']

好了,看到這裏對於map+lambda的用法大家已經很清楚了應該~

lambda + filter

lambda和filter的組合也很常見,用於特定篩選條件下,現在讓我們來看上篇文章filter的例子,就應該很好理解了:

numbers = [0, 1, 2, -3, 5, -8, 13]

# 提取奇數
result = filter(lambda x: x % 2, numbers)
print("Odd Numbers are :",list(result))

# 提取偶數
result = filter(lambda x: x % 2 == 0, numbers)
print("Even Numbers are :",list(result))

#提取正數
result = filter(lambda x: x>0, numbers)
print("Positive Numbers are :",list(result))

Out:Odd Numbers are : [1, -3, 5, 13]
     Even Numbers are : [0, 2, -8]
     Positive Numbers are : [1, 2, 5, 13]

這裏無非就是我們把filter(fun,sequence)裏面的fun換成了我們的lambda,只是lambda的函數部分(x%2,x%2==0,x>0)都是可以返回True或者False來判斷的,符合fiter的要求,用剛纔李雷和韓梅梅的例子也是一個道理:

person =[{'name':'Lilei',
          'city':'beijing'},
         {'name':'HanMeiMei',
          'city':'shanghai'}]

names=list(filter(lambda x:x['name']=='Lilei',person)) # 提取李雷的信息
print(names)

Out:[{'name': 'Lilei', 'city': 'beijing'}]

lambda + reduce

還是讓我們看一下上篇文章的例子:

from functools import reduce          # Only Python 3
numbers = [1,2,3,4]
result_multiply = reduce((lambda x, y: x * y), numbers)
result_add = reduce((lambda x,y: x+y), numbers)

print(result_multiply)
print(result_add)

Out:24
     10

這個例子用lambda和reduce的配合實現了list求累積和和累積乘法。
有意思的是這個例子具有兩面性,一方面展示了lambda和reduce如何一起使用,另一方面也引出了接下來我想說的重點:lambda真的值得用嗎?到底應該怎麼用?

避免過度使用lambda

通過上面的例子大家已經看到了lambda的實際應用場景,但是這裏我想和大家分享一下我的看法:我認爲lambda的缺點略多於優點,應該避免過度使用lambda

首先,這僅僅是我的個人看法哈,希望大家理解,我的理由如下:首先讓我們拿lambda方法和常規def做個對比,我發現lambda和def的主要不同點如下:

  • 可以立即傳遞(無需變量)
  • 只需一行代碼,簡潔(未必高效)
  • 可以會自動返回,無需return
  • lambda函數沒有函數名稱

有關優點大家都可以看到,我主要想說一下它的缺點,首先,從真正需求出發,我們在大多數時候是不需要lambda的,因爲總可以找到更好的替代方法,現在我們一起看一下剛纔lambda+reduce 的例子,我們用lambada實現的結果如下:

from functools import reduce          # Only Python 3
    numbers = [1,2,3,4]
    result_multiply = reduce((lambda x, y: x * y), numbers)
    result_add = reduce((lambda x,y: x+y), numbers)

這裏用lambda並沒有實現簡單高效的目的,因爲我們有現成的sum和mul方法可以用:


from functools import reduce
from operator import mul

numbers = [1,2,3,4]
result_add = sum(numbers)
result_multiply =reduce(mul,numbers)

print(result_add)
print(result_multiply)

Out: 10
     24

結果是一樣的,但是顯然用sum和mul的方案更加高效。再舉個常見的例子說明,假如我們有一個list存儲了各種顏色,現在要求把每個顏色首字母大寫,如果用lambda寫出是這樣:

colors = ['red','purple','green','blue']
result = map(lambda c:c.capitalize(),colors)
print(list(result))

Out:['Red', 'Purple', 'Green', 'Blue']

看着似乎不錯,挺簡潔的,但是我們有更好的方法:


colors = ['red','purple','green','blue']
result = [c.capitalize() for c in colors]
print(result)

Out:['Red', 'Purple', 'Green', 'Blue']

用sorted還能處理首字母不規範的情況,連排序都省了:

colors = ['Red','purple','Green','blue']
print(sorted(colors,key=str.capitalize))

Out:['blue', 'Green', 'purple', 'Red']

還有一個主要原因就是: lambda函數沒有函數名稱。所以在代碼交接,項目移植的場景中會給團隊帶來很多困難,多寫個函數add_one()沒什麼壞處,因爲大家都很容易理解,知道它是執行+1的功能

適合lambda的場景

話又說回來,存在即合理,那麼真正需要我們使用lambda的是哪些場景呢:

  1. 你需要的方法是很簡單的(+1,字符串拼接等),該函數不值得一個名字
  2. 使用lambda表達式,會比我們能想到的函數名稱更容易理解
  3. 除了lambda,沒有任何python提供的函數可以實現目的
  4. 團隊中所有成員都掌握lambda,這樣不會造成歧義或浪費時間

還有一種場景非常適用,就是在給其他人制造自己很專業的錯覺時,比如:

哎呀,小老弟,聽說你學了Python,知道lambda不? 沒聽過?不行啊,白學了!來來來,讓我給你講講。。。此處省略1萬字

總結

今天爲大家九淺一深地講解了lambda的用法和使用場景,所謂九淺一深,就是90%情況下用於創建簡單的匿名函數,10%的情況稍微複雜(我這個藉口找的太好了)

總而言之就是,任何事情都具有兩面性,我們在使用lambda之前應該先停下來,問問自己是不是真的需要它。

當然,如果需要和別人忽悠的時候都是正反一張嘴,lambda是好是壞全憑一張嘴了,吹牛時請遵守如下原則,屢試不爽:

如果你說一個女大學生晚上賣淫就是可恥,但如果改成一個妓女利用業餘時間努力學習就勵志多了

lambda也是如此

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章