匿名函數lambda, 你搞清楚 了嗎?
lambda 函數 形式
lambda 表達式(有時稱爲 lambda 構型)被用於創建匿名函數。
匿名函數 一般形式
# 以下表達式 會產生一個函數對象
lambda arguments: expression
該未命名對象的行爲類似於用以下方式定義的函數:
函數形式
def <lambda>(arguments):
return expression
通過這個形式, 基本上就知道如何使用了, 以及各個位置的作用
注意
注意通過 lambda 表達式創建的函數不能包含語句或標註
示例:
場景一
可以用 lambda 關鍵字來創建一個小的匿名函數。這個函數返回兩個參數的和: lambda a, b: a+b 。Lambda函數可以在需要函數對象的任何地方使用。它們在語法上限於單個表達式。從語義上來說,它們只是正常函數定義的語法糖。與嵌套函數定義一樣,lambda函數可以引用所包含域的變量:
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
上面的例子使用一個lambda表達式來返回一個函數。另一個用法是傳遞一個小函數作爲參數:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
場景二
有一個鍵爲字符串格式的數字的字典, 需要按照數字的大小從小到大進行排序
test_dict = {'2': '2', '6': '0', '5': '5', '4': '1', '3': '4', '1': '2'}
# lambda 示例 可通過sorted reverse設置升序 還是降序
print(dict(sorted(test_dict.items(), key=lambda x: int(x[0]))))
# 錯誤示例
print(dict(sorted(test_dict.items())))
# 結果輸出
{'1': '2', '2': '2', '3': '4', '4': '1', '5': '5', '6': '0'}
{'1': '2', '2': '2', '3': '4', '4': '1', '5': '5', '6': '0'}
# 對於錯誤示例,大家可以看到結果是一樣的。那你測試一下下面的示例
test_dict = {'1': ['2', '2', '0'], '4': ['0', '1', '1'], '3': ['4', '4', '4'], '6': ['0', '0', '2'], '2': ['2', '2', '2'], '5': ['5', '5', '5']}
使用建議
需要編寫很小的函數, 且Python未內置該方法
如有Python內置的類似函數, 不建議用lambda。內置的效率會更高
編寫函數式風格程序時,你會經常需要很小的函數,作爲謂詞函數或者以某種方式來組合元素。
如果合適的 Python 內置的或者其他模塊中的函數,你就一點也不需要定義新的函數:
stripped_lines = [line.strip() for line in lines]
existing_files = filter(os.path.exists, file_list)
如果不存在你需要的函數,你就必須自己編寫。一個編寫小函數的方式是使用 lambda 表達式。lambda 接受一組參數以及組合這些參數的表達式,它會創建一個返回表達式值的匿名函數:
adder = lambda x, y: x+y
print_assign = lambda name, value: name + ‘=’ + str(value)
另一種替代方案就是通常的使用 def 語句來定義函數:
def adder(x, y):
return x + y
def print_assign(name, value):
return name + '=' + str(value)
哪一種更受青睞呢?這是一個風格問題;我通常的做法是避免使用 lambda。
我這麼偏好的一個原因是,lambda 能夠定義的函數非常受限。函數的結果必須能夠作爲單獨的表達式來計算,這意味着你不能使用多路 if... elif... else
比較,或者 try... except
語句。如果你嘗試在 lambda 語句中做太多事情,你最終會把表達式過於複雜以至於難以閱讀。你能快速的說出下面的代碼做了什麼事情嗎?:
import functools
total = functools.reduce(lambda a, b: (0, a[1] + b[1]), items)[1]
你可以弄明白,不過要花上時間來理清表達式來搞清楚發生了什麼。使用一個簡短的嵌套的 def 語句可以讓情況變得更好:
import functools
def combine(a, b):
return 0, a[1] + b[1]
total = functools.reduce(combine, items)[1]
如果我僅僅使用一個 for 循環會更好:
total = 0
for a, b in items:
total += b
或者使用內置的 sum() 和一個生成器表達式:
total = sum(b for a, b in items)
許多使用functools.reduce()
的情形可以更清晰地寫成 for 循環的形式。
Fredrik Lundh 曾經建議以下一組規則來重構 lambda 的使用:
- 寫一個 lambda 函數。
- 寫一句註釋來說明這個 lambda 究竟幹了什麼。
- 研究一會這個註釋,然後想出一個抓住註釋本質的名字。
- 用這個名字,把這個 lambda 改寫成 def 語句。
- 把註釋去掉。