你所不知道的Python | 函式引數的演進之路

simpleapples發表於2019-02-27

函式引數處理機制是Python中一個非常重要的知識點,隨著Python的演進,引數處理機制的靈活性和豐富性也在不斷增加,使得我們不僅可以寫出簡化的程式碼,也能處理複雜的呼叫。

關鍵字引數

呼叫時指定引數的名稱,且與函式宣告時的引數名稱一致。

關鍵字引數是Python函式中最基礎也最常見的,我們寫一個記賬的函式,引數是需要記錄的時間和金額。

def add_record(date, amount):
	print(`date:`, date, `amount:`, amount)
複製程式碼

這裡的amount引數就是一個關鍵字引數,關鍵字引數支援兩種呼叫方式:

  • 位置呼叫
  • 關鍵字呼叫

位置呼叫,就是按引數的位置進行呼叫,例如傳入兩個引數,第一個是字串2018-07-06,第二個是整數10,那麼這兩個引數會被分別賦予date和amount變數,如果順序反過來,則這兩個引數分別賦予amount和date變數。

add_record(`2018-07-06`, 10)  # 輸出date: 2018-07-06 amount: 10
add_record(10, `2018-07-06`)  # 輸出date: 10 amount: 2018-07-06
複製程式碼

關鍵字呼叫,可以忽略引數順序,直接指定引數。

add_record(amount=10, date=`2018-07-06`)  # 雖然引數順序反了,但是使用了關鍵字呼叫,所以依然輸出date: 2018-07-06 amount: 10
複製程式碼

僅限關鍵字引數

我們定義一個Person類,並實現它的__init__方法

class Person(object):
	def __init__(self, name, age,  gender, height, weight):
		self._name = name
		self._age = age
		self._gender = gender
		self._height = height
		self._weight = weight
複製程式碼

當初始化這個類的時候,我們可以使用關鍵字呼叫,也可以使用位置呼叫。

Person(`Wendy`, 24, `female`, 160, 48)
Person(`John`, age=27, gender=`male`, height=170, weight=52)
複製程式碼

對比上面兩種方式,我們會發現引數多的時候通過關鍵字指定引數不僅更加清晰,也更具有可讀性。如果我們希望函式只允許關鍵字呼叫,該如何做呢?Python 3.0中,引入了一種新的僅限關鍵字引數,能實現我們的需求。

下面將age以後的引數修改為只允許關鍵字呼叫,定義函式時想指定僅限關鍵字引數,要把它們放到前面有星號的引數後面,在Python中有星號的引數是可變引數的意思,如果不想支援可變引數,可以在引數中放一個星號作為分割。

class Person(object):
        # 引數中的星號作為關鍵字引數和僅限關鍵字引數的分割
	def __init__(self, name, *, age=`22`, gender=`female`, height=160, weight=50):
		self._name = name
		self._age = age
		self._gender = gender
		self._height = height
		self._weight = weight

Person(`Wendy`, 24, `female`, 160, 48)  # 報錯,age以後引數不允許位置呼叫
Person(`John`, age=27, gender=`male`, height=170, weight=52)  # 正常執行
複製程式碼

普通引數和僅限關鍵字引數中間由一個星號隔離開,星號以後的都是僅限關鍵字引數,只可以通過關鍵字指定,而不能通過位置指定。

引數預設值

在函式宣告時,指定引數預設值,呼叫時不傳入引數則使用預設值,相當於可選引數。

def add_record(date, amount=0):
	print(`date:`, date, `amount:`, amount)

add_record(`2018-07-06`)  # 輸出date: 2018-07-06 amount: 0
複製程式碼

上面程式碼中沒有傳入amount引數,所以amount直接被置為預設值0。有一點需要注意的是,預設引數需要設定在必選引數後面,並且預設引數既可以通過位置呼叫,也可以通過關鍵字呼叫。

add_record(`2018-07-06`, 10)  # 通過位置指定引數
add_record(`2018-07-06`, amount=10)  # 通過位置指定引數
add_record(amount=10, `2018-07-06`)  # 報錯,預設引數必須在必選引數後面
複製程式碼

引數預設值既支援關鍵字引數,也支援僅限關鍵字引數。

可變長引數

“可變長”顧名思義是允許在呼叫時傳入多個引數,可變長引數適用於引數數量不確定的場景,可變引數有兩種,一種是關鍵字可變長引數,另一種是非關鍵字可變長引數。

非關鍵字可變長引數的寫法是在引數名前加一個星號,Python會將這些多出來的引數的值放入一個元組中,由於元組中只有引數值而沒有引數名稱,所以是非關鍵字引數。

def print_args(*args):
	print(args)

print_args(1, 2, 3, 4, 5)  # 輸出元組(1, 2, 3, 4, 5)

a = [1, 2, 3, 4, 5]
print_args(a)  # 直接傳入時,列表a會被當作一個元素,所以輸出([1, 2, 3, 4, 5],)
print_args(*a)  # 在傳參時加星號可以將可迭代引數解包,所以列表a中每一個元素都被當作一個引數傳入,輸出(1, 2, 3, 4, 5)
複製程式碼

關鍵字可變長引數的寫法是在引數名前加兩個星號,Python會將這些多出來的引數的值放入一個字典中,由於字典中只有引數值而沒有引數名稱,所以是關鍵字引數。

def print_kwargs(**kw_args):
	print(kw_args)

a = {`a`: 1, `b`: 2, `c`: 3, `d`: 4, `e`: 5}
print_kwargs(**a)  # 使用關鍵字可變引數時, {`a`: 1, `c`: 3, `b`: 2, `e`: 5, `d`: 4}
複製程式碼

函式註解

Python 3中為函式定義增加的另一個新功能是函式註解,所謂函式註解,就是可以在函式引數和返回值上新增任意的後設資料。

def create_person(name: str, age: int, gender: str = `female`, height: int = 160)  -> bool:
	return True
複製程式碼

用create_person方法舉例,可以看到在每個引數後面都跟了一個引數型別,在函式後面則是返回值型別,函式註解可以用在文件編寫、型別檢查中,在支援函式註解的IDE中,如果傳入引數和返回的型別不符合函式註解中的型別,IDE會提示錯誤。

但是函式註解只是一個後設資料,Python直譯器執行時候並不會去檢查型別,所以下面這種情況也是合法的。

Person(name=123, age=`John`)  # 並不會報錯
複製程式碼

總結

Python有著非常好入門的特點,但是隨著語言本身的演進,很多高階功能也在持續加入,用好這些功能可以使我們的Python程式碼擁有更高的可讀性,適應更加複雜的應用場景。

你所不知道的Python | 函式引數的演進之路

掃碼關注【Python私房菜】,我會在這裡持續釋出Python相關原創技術文章

相關文章