1. 程式人生 > Python入門教學 >23 Python 的 lambda 表示式

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,包含 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 函式是一個非常好的選擇。