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,包含 3 個元素 1、2、3
- 調用函數 map 時,需要提供一個函數 y = f (x),函數 f 將輸入 x 映射為輸出 y
- 將函數 f 對圖的左邊的序列中的每個元素依次作用,得到圖的右邊的序列
- 圖的右邊是一個序列 list,包含 3 個元素 f (1)、f (2)、f (3)
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 函數是一個非常好的選擇。