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