一級函式、lambda 運算式
April 20, 2022在 Python 中,函式不單只是個定義,還是個值,被定義的函式會產生函式物件,它是 function
的實例。
一級函式
既然函式是物件,也就可以指定給其他的變數。例如:
>>> def max(num1, num2):
... return num1 if num1 > num2 else num2
...
>>> maximum = max
>>> maximum(10, 5)
10
>>> type(max)
<class 'function'>
>>>
上面在定義了 max
函式之後,透過 max
名稱將函式物件指定給 maximum
名稱,無論透過 max
或者 maximum(10, 5)
,結果都是呼叫了它們參考的函式物件。
函式跟數值、list
、set
、dict
、tuple
等一樣,都被 Python 視為一級公民來對待,可以自由地在變數、函式呼叫時指定,因此具有這樣特性的函式,也被稱一級函式(First-class function),函式代表著某個可重用流程的封裝,當它可以作為值傳遞時,就表示可以將某個可重用流程進行傳遞,這是個極具威力的功能。
來看個一級函式傳遞的例子,到目前為止,經常會使用 list
、tuple
等有序結構,有時會想排序其中的元素,這時可以使用 sorted
函式,它可以針對你指定的方式進行排序。例如:
>>> sorted([2, 1, 3, 6, 5])
[1, 2, 3, 5, 6]
>>> sorted([2, 1, 3, 6, 5], reverse = True)
[6, 5, 3, 2, 1]
>>> sorted(('Justin', 'openhome', 'momor'), key = len)
['momor', 'Justin', 'openhome']
>>> sorted(('Justin', 'openhome', 'momor'), key = len, reverse = True)
['openhome', 'Justin', 'momor']
>>>
sorted
會傳回新的 list
,其中包含了排序後的結果,key
參數可用來指定針對什麼特性來迭代,例如在指定 len
函式時,每個元素都會傳入 len
運算,得到的長度值再作為排序依據。
如果是可變動的 list
,本身也有個 sort
方法,這個方法會直接在list本身排序,不像 sorted
方法會傳回新的 list
。例如:
>>> lt = [2, 1, 3, 6, 5]
>>> lt.sort()
>>> lt
[1, 2, 3, 5, 6]
>>> lt.sort(reverse = True)
>>> lt
[6, 5, 3, 2, 1]
>>> names = ["Justin", "openhome", "momor"]
>>> names.sort(key = len)
>>> names
['momor', 'Justin', 'openhome']
>>>
lambda 運算式
在之前的排序範例中,直接使用了 len
函式,依長度來排序,如果想針對最後一個字母排序呢?
>>> def last(name):
... return name[-1]
...
>>> sorted(('Justin', 'openhome', 'momor'), key = last)
['openhome', 'Justin', 'momor']
>>>
函式本體只是個簡單的運算式,使用 def
顯得有點大費周章了,如果函式本體很簡單,只有一句簡單的運算,對於這類情況,可以考慮使用 lambda
運算式。例如:
>>> sorted(('Justin', 'openhome', 'momor'), key = lambda name: name[-1])
['openhome', 'Justin', 'momor']
>>>
在 lambda
關鍵字之後定義的是參數,而冒號 :
之後定義的是函式本體,運算結果會作為傳回值,不需要加上 return
,像 lambda name: name[-1]
這樣的 lambda
運算式會建立 function
實例,也就是一個函式,有時臨時只是需要個小函式,使用 lambda
就很方便。
如果 lambda
不需要參數,直接在 lambda
後加上冒號就可以了,若需要兩個以上的參數,中間要使用逗號 ,
區隔。例如:
>>> max = lambda n1, n2: n1 if n1 > n2 else n2
>>> max(10, 5)
10
>>>
相較於其他語言中的 lambda
語法,Python 使用 lambda
關鍵字的方式,其實並不簡潔,甚至有點妨礙可讀性, Python 的 lambda
也沒辦法寫太複雜的邏輯,這是 Python 為了避免 lambda
被濫用而特意做的限制,如果覺得可讀性不佳,或者需要撰寫更複雜的邏輯,請乖乖地使用 def
定義函式,並給予一個清楚易懂的函式名稱。
在 Python 中,會看到不少 API 可以接受函式,不過嚴格來說,是接受 callable 物件,也就是行為上像函式可以呼叫的物件,具體而言,就是實作了 __call__
方法的物件,從 API 設計者角度來看,一個 callable 物件是以函式或類別定義並不重要,這讓 API 在使用上可以有更多的彈性。