23 Python 的 lambda 表示式
在很多資料中,經常會看到這樣一句話:“Python 中的函式是第一類物件”。關於這一點,Python 的創始人 Guido 曾提過 “First-class Everything”,他對 Python 的一個發展目標就是所有的物件都是第一類物件。
1. 將函式作為第一類物件
1.1 什麼是第一類物件
在前言中所說的第一類物件,其實是指函式作為一個物件,與其它物件具有相同的地位。具體來說,數值可以被賦值給變數、作為引數傳遞給函式、作為返回值,因為函式和數值具有相同的地位,所以函式也可以被賦值給變數、作為引數傳遞給函式、作為返回值。
Python 中的常見型別物件包括:
- 數值,例如:123、3.14
- 字串,例如:“Hello”、“World”
- 布林值,例如:True、False
- 列表,例如:[1, 2, 3]
- 字典,例如:{‘name’: ‘tom’, ‘age’: 12}
可以在如下場合中處理這些物件,包括:
1.1.1 將物件賦值給變數
可以將數值、字串、列表、字典型別的物件賦值給變數,例如:
number = 123
string = "hello"
list = [1, 2, 3]
dict = {'name': 'tom', 'age': 12}
1.1.2 將物件作為引數傳遞
可以將數值、字串、列表、字典型別的物件作為引數傳遞給函式,例如:
print(123)
print ("hello")
print([1, 2, 3])
print({'name': 'tom', 'age': 12})
1.1.3 將物件用作返回值
可以將數值、字串、列表、字典型別的物件作為函式的返回值,例如:
def return_number():
return 123
def return_string():
return "hello"
def return_list():
return [1, 2, 3]
def return_dict():
return {'name': 'tom', 'age': 12}
1.2 將函式作為第一類物件
將函式作為第一類物件,函式具有和數值、字串、列表、字典等型別的物件具有相同的地位,因此:
1.2.1 可以將函式賦值給變數
def max(a, b):
if a > b:
return a
else:
return b
var = max
print('max = %d' % var(1, 2))
- 在第 1 行,定義函式 max
- 在第 7 行,將函式 max 作為值賦予變數 var
- 在第 8 行,變數 var 的型別是函式,因此可以進行函式呼叫
程式的輸出結果如下:
max = 2
1.2.2 可以將函式作為引數傳遞
def func():
print('Inside func')
def pass_func(data):
print('Inside pass_func')
data()
pass_func(func)
- 在第 1 行,定義函式 func
- 在第 4 行,定義函式 pass_func,函式 pass_func 的引數 data 的型別是函式
- 在第 6 行,呼叫函式 data(),data 的型別是函式,因此可以進行函式呼叫
- 在第 8 行,將函式 func 作為引數傳遞給函式 pass_func
程式的輸出結果如下:
Inside pass_func
Inside func
1.2.3 可以將函式作為返回值
def func():
print('Inside func')
def return_func():
print('Inside return_func')
return func
var = return_func()
var()
- 在第 1 行,定義函式 func
- 在第 4 行,定義函式 return_func,函式 return_func 返回一個函式型別的物件
- 在第 6 行,將函式 func 作為值返回
- 在第 8 行,呼叫 return_func(),將函式的返回值儲存到變數 var
- 在第 9 行,變數 var 的型別是函式,因此可以進行函式呼叫
程式的輸出結果如下:
Inside return_func
Inside func
2. 將函式作為第一類物件的意義
將函式作為第一類物件,是一種重要的抽象機制,極大的提升了程式的靈活性。通過一個例子進行說明。假設需要完成這樣的任務:
- 存在一個列表 [1, -1, 2, -2, 3, -3]
- 列印輸出列表中的正數
- 列印輸出列表中的負數
我們使用兩種方法實現:
- 包含重複性程式碼的解決方法
- 將函式作為引數傳遞
2.1 包含重複性程式碼的解決方法
list = [1, -1, 2, -2, 3, -3]
def print_positive(list):
for item in list:
if item > 0:
print(item)
def print_negative(list):
for item in list:
if item < 0:
print(item)
print_positive(list)
print_negative(list)
- 在第 3 行,定義了函式 print_positive,該函式列印 list 中的正數
- 在第 8 行,定義了函式 print_negative,該函式列印 list 中的負數
- 對比函式 print_positive 和函式 print_negative,兩者的相似度很高
- 程式碼的結構完全相同
- 遍歷 list 時,兩者的選擇條件不一樣,print_positive 使用 item > 0 的條件選擇,print_negative 使用 item < 0 的條件選擇
程式的輸出結果如下:
1
2
3
-1
-2
-3
2.2 將函式作為引數傳遞
list = [1, -1, 2, -2, 3, -3]
def select_positive(x):
return x > 0
def select_negative(x):
return x < 0
def select(list, select_function):
for item in list:
if select_function(item):
print(item)
select(list, select_positive)
select(list, select_negative)
- 在第 3 行,定義了函式 select_postive,如果引數 > 0,則返回真
- 在第 6 行,定義了函式 select_negative,如果引數 < 0,則返回真
- 在第 9 行,定義了函式 select,包含兩個引數,第 1 個引數是列表,第 2 個引數的型別是函式
- 在第 10 行,遍歷列表 list
- 在第 11 行,引數 selct_function 是一個函式,用於選擇是否選中當前正在遍歷的數值
- 在第 14 行,將函式 select_positive 作為引數傳遞給函式 select,函式列印列表中的正數
- 在第 15 行,將函式 select_negative 作為引數傳遞給函式 select,函式列印列表中的負數
程式的輸出結果如下:
1
2
3
-1
-2
-3
3. 匿名函式 lambda
3.1 lambda 表示式的定義
在傳入函式時,有些時候,不需要顯式地定義函式,直接傳入匿名函式更方便。Python 提供了 lambda 表示式對匿名函式提供了有限支援,lambda 表示式的語法如下:
lambda args: expression
使用 lambda 表示式定義一個函式,函式判斷輸入引數是否大於 0,如下所示:
lambda x: x > 0
該函式等價於函式 select_positive,如下所示:
def select_positive(x):
return x > 0
函式 select_positive 與 lambda 表示式的功能相同,函式 select_positive 具有函式名稱,lambda 表示式沒有函式名,因此 lambda 表示式又被稱為匿名函式。
3.2 使用 lambda 表示式重寫程式
在前面的小節中,將函式作為引數,編寫程式實現列印正數和負數。下面使用 lambda 表示式重寫這個程式:
list = [1, -1, 2, -2, 3, -3]
def select(list, select_function):
for item in list:
if select_function(item):
print(item)
select(list, lambda item: item > 0)
select(list, lambda item: item < 0)
- 在第 3 行,定義了函式 select,它與前面的小節定義的函式完全相同
- 在第 4 行,遍歷列表 list
- 在第 5 行,引數 selct_function 是一個函式,用於選擇是否選中當前正在遍歷的數值
- 在第 8 行,定義了 lambda 表示式
- lambda 表示式判斷輸入引數是否為正數
- 將 lambad 表示式作為引數傳遞給函式 select,函式列印列表中的正數
- 在第 9 行,定義了 lambda 表示式
- lambda 表示式判斷輸入引數是否為負數
- 將 lambad 表示式作為引數傳遞給函式 select,函式列印列表中的負數
程式輸出結果如下:
1
2
3
-1
-2
-3
3.3 map 函式
使用 Python 內建的 map 函式時,通常會用到 lambda 表示式。map 函式的原型如下:
map(function, list)
map 函式接收兩個引數 function 和 list,function 是一個函式,list 是一個可以被遍歷的序列,map 將傳入的函式依次作用到序列的每個元素,並把結果作為新的序列返回。map 函式的工作原理圖如下:
list = [1, 2, 3]
list2 = map(lambda x: x * 2, list)
for item in list2:
print(item)
list10 = map(lambda x: x + 10, list)
for item in list10:
print(item)
- 在第 1 行,定義原始序列 list
- 在第 3 行,定義 lambda 函式,作用於 list 中的每個元素,將每個元素乘以 2,生成一個新序列 list2
- 在第 4 行,列印輸出新序列 list2
- 在第 7 行,定義 lambda 函式,作用於 list 中的每個元素,將每個元素加上 10,生成一個新序列 list10
- 在第 8 行,列印輸出新序列 list10
程式輸出結果如下:
2
4
6
11
12
13
4. 小結
Python 對 lambda 函式 的支援有限。當我們在編寫程式的時候如果程式碼只是用一次,並不會複用的時候 lambda 函式是一個非常好的選擇。