【一不小心就學會Python Lambda匿名函數的3個要點】

2023/09/12閱讀時間約 12 分鐘

你會在程式裡面寫函數嗎?

通常寫函數的第一個問題,就是要給函數取名字。

名字取得不好,後來調用函數不自然,就會拖垮整個寫程式的效率。

為函數命名,也是一門技術,好的函數命名,就能提高函數被重複使用的頻率。

然而,也是在某些情況下,我們需要「一次性函數」。

沒錯,用完即丟的函數。

這時候就需要Lambda。

raw-image

學習Lambda是一件其實不會太困難的事情,具體你可以往這三個方面學習:

▋1. lambda是一種回傳數據特定形式的匿名函數。

▋2. 定義一個lambda需要指定參數(Parameters)與表達(Expression)

▋3. lambda的關鍵用法,是在將一個函數作為參數輸入另一個函數,也就是執行泛函操作

而這是我理解這3個方面的方式:

❏ lambda是一種回傳數據特定形式的匿名函數。

lambda 是所謂的「匿名函數 (Anonymous Function)」。

根據維基百科,「匿名函數」是一種不需要與識別符(Identifier)作綁定(Bound)的函數。^[an anonymous function (function literal, lambda abstraction, lambda function, lambda expression or block) is a function definition that is not bound to an identifier.]

這裡的識別符,就是函數的名字;而綁定就是將函數匹配到名字的字串上。

透過 lambda,我們可以省下命名一個函數的工,然後把lambda運算完的結果,儲存到另一個變數中。

這樣的過程十分管用,尤其是在想要對向量或者字典做高階函數運算的時候。

案例一:使用 map 來對列表的每一個元素進行平方運算。

要將每個元素平方,但其實不用再額外寫一個「平方函數」,透過lambda,直接用map就可以作用。

squared = map(lambda x: x**2, [1, 2, 3, 4])
print(list(squared)) # 輸出會是 [1, 4, 9, 16]

案例二:使用 filter 來過濾出列表中大於 10 的元素。

要比大小,直觀事先對每個元素比大小,把比大小結果的1與0翻譯回來。但透過lambda,可以省去for迴圈以及比大小的過程。

filtered = filter(lambda x: x > 10, [5, 11, 3, 12])
print(list(filtered)) # 輸出會是 [11, 12]

案例三:使用sorted 來依照特定規則排序一個元組列表。

要給元組排序是一件苦差事,你要先指定維度,然後在一個一個去比。但透過lambda,可以直接搭配sorted來拿到結果,不用額外寫一個函數去一個一個比。

pairs = [(1, 'one'), (4, 'four'), (3, 'three'), (2, 'two')]
sorted_pairs = sorted(pairs, key=lambda x: x[1])
print(sorted_pairs) # 輸出會是 [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

原則上,掌握lambda,你可以寫出更簡潔的Python code,也可以提高可用性。lambda尤其是在處理trivial的運算特別好用!

❏ 定義一個lambda需要指定參數(Parameters)與表達(Expression)

要創造lambda,其語法是

lambda parameters:expression

其中

  • 參數 (Parameters):是lambda函數要操作的數據
  • 表達(Expression):是lambda函數要返還的數據

會寫lambda非常有用,可以客製化很多簡單的運算。

例子一:乘法

multiply = lambda x, y: x * y
print(multiply(5, 3)) # Output: 15

例子二:最大值

maximum = lambda x, y: x if x > y else y
print(maximum(5, 8)) # Output: 8

例子三:反轉布林值

negate = lambda x: not x
print(negate(True)) # Output: False
print(negate(False)) # Output: True

例子四:字符串拼接

concatenate = lambda str1, str2: str1 + str2
print(concatenate("Hello, ", "world!")) # Output: Hello, world!

例子五:串連三個字串的第一個元素

concat_strings = lambda a, b, c: a[0] + b[0] + c[0] 
print(concat_strings("World", "Wide", "Web"))

例子六:拿列表的第一個元素

first_element = lambda x: x[0] if len(x) > 0 else "List is empty"
print(first_element([1, 2, 3])) # Output: 1
print(first_element([])) # Output: List is empty

妥善去使用lambda,甚至可以把程式代碼變得更加口語化,讓各種抽象的操作變得更加簡潔,非常值得學習。

❏ lambda的關鍵用法,是在將一個函數作為參數輸入另一個函數,也就是執行泛函操作

泛函(Functional)是一種以「函數」為定義域的映射。

也就是說,每一個泛函要運算時,都要輸入一個函數作為參數,然後輸出我們需要的資訊。

例子一:樣本變異

舉一個統計中常見的例子,是計算「樣本變異 (Sample Variance)」。

將計算樣本變異看為泛函操作,那所需要輸入的函數其實是「取平均後開根號」,因為樣本變異是平均數(平均值)周圍數據點變動的一種度量。簡單來說,樣本變異是數據點與平均值的差值平方的平均。在這個情境下,"取平均後開根號" 的函數可以被看作是一個泛函的參數。

如果將這個操作使用 Python 來實現,我們可以用 lambda 函數來表達:

# 一個簡單的平均數函數
average = lambda arr: sum(arr) / len(arr)

# 樣本變異的泛函
def sample_variance_functional(f, data):
mean = f(data) # 使用輸入的函數計算平均數
return sum((x - mean)**2 for x in data) / (len(data) - 1)

# 使用泛函計算樣本變異
data = [1, 2, 3, 4, 5]
result = sample_variance_functional(average, data)
print("Sample Variance:", result)

在這個例子中,sample_variance_functional 是一個泛函,它接受一個函數 f 和一個數據集 data,然後計算該數據集的樣本變異。這個泛函使用了輸入的函數 f(在這裡是 average)來計算數據集的平均數,然後用這個平均數去計算樣本變異。

這個例子展示了 lambda 函數和泛函的概念是如何結合在一起的。通過這種方式,我們可以將各種不同的函數(比如加權平均,中位數等)作為 sample_variance_functional 的參數,來計算相對應的樣本變異。

這提供了高度的靈活性和可擴展性。我們可以把輸入的函數f替換成其他的函數,可以是weighted_average或者是其他形式的平均,如此來討論更廣義的「變異數 (Variance)」觀念。

例子二:得到一組數字的平方根

假設我們有一個數組,我們想對這個數組的每一個元素取平方根。我們可以定義一個泛函,這個泛函接受一個函數(這裡是取平方根的函數)和一個數組,然後返回一個新的數組。

import math

# 定義一個泛函,這個泛函接受一個函數 f 和一個列表 lst
def map_functional(f, lst):
return list(map(f, lst))

# 使用 lambda 函數定義取平方根的操作
sqrt_function = lambda x: math.sqrt(x)

# 定義一個數組
numbers = [1, 4, 9, 16, 25]

# 使用泛函計算數組的平方根
sqrt_numbers = map_functional(sqrt_function, numbers)
print("Square roots:", sqrt_numbers)

在這個例子中,map_functional 是一個泛函,它接受一個函數 f 和一個列表 lst。這個泛函用 map 函數來對列表 lst 的每一個元素應用函數 f,然後返回一個新的列表。

這樣,我們就可以使用不同的函數(不只是取平方根)來轉換 numbers 列表。這提供了高度的靈活性,允許我們輕鬆地替換處理數據的邏輯。

例子三:過濾出偶數

我們可以使用 filterlambda 函數來過濾一個列表中的元素。這裡的例子是一個泛函,它接受一個判斷函數(predicate function)和一個列表,然後返回一個只包含符合條件的元素的新列表。

# 定義一個泛函,這個泛函接受一個函數 f 和一個列表 lst
def filter_functional(f, lst):
return list(filter(f, lst))

# 使用 lambda 函數定義一個判斷是否為偶數的函數
is_even = lambda x: x % 2 == 0

# 定義一個整數列表
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 使用泛函過濾出偶數
even_numbers = filter_functional(is_even, numbers)
print("Even numbers:", even_numbers)

在這個例子中,filter_functional 是一個泛函,它接受一個函數 f 和一個列表 lst。然後它用 filter 函數來過濾出列表 lst 中符合函數 f 條件的元素。

這樣,我們就可以使用不同的判斷函數來過濾 numbers 列表,這提供了很高的靈活性。例如,我們可以簡單地更換 lambda 函數,以過濾出大於 5 的所有數字,或者能被 3 整除的數字等等。

如此,只要能活用lambda,搭配上泛函的框架,就能操作各式各樣稍微複雜的數學操作!掌握lambda思維,就能掌握計算數學的能力!

▋寫在最後

學習如何正確地使用 lambda 函數和泛函是一個值得投資的時間和努力的過程。他們不僅可以幫助你寫出更簡潔、更高效的程式碼,而且也能提供更高的靈活性和可擴展性。

通過這篇文章,我們探討了以下三個方面:

  1. lambda 是一種特定形式的匿名函數,它可以讓我們快速地定義簡單的一次性函數。
  2. lambda 函數的定義需要指定參數和表達式,這讓我們能夠根據需要自定義各種運算。
  3. lambda 函數與泛函的組合使用可以讓我們以一種更抽象和通用的方式來處理問題。

透過實例和代碼,你也看到了這些與lambda相關的概念是如何具體應用的。希望這能幫助你更好地理解和使用 lambda 函數,並在你的程式設計之旅中找到它們的價值!

347會員
694內容數
Outline as Content
留言0
查看全部
發表第一個留言支持創作者!