Function,表示子例程的一般性名詞。在某些程式設計語言中,它指帶傳回值的子例程或語句。在一些程式設計語言中起着關鍵字的作用。
在Python中,function是非常重要而且常見的,一般擷取類或函數的參數資訊。
在Python中,function一般有如下幾類:
一、POSITIONAL_OR_KEYWORD
如果沒有任何*的聲明,那麼就是POSITIONAL_OR_KEYWORD類型的,如同語義一樣,POSITIONAL_OR_KEYWORD類型的參數可以通過位置POSITIONAL傳參調用,也可以過關鍵字KEYWORD傳參。以下是一個最簡單的例子:
def foo(a):
pass
# 位置傳參調用
foo(1)
# 關鍵字傳參調用
foo(a=1)
二、VAR_POSITIONAL
第二種是可變的位置參數,通過一個*字首來聲明,如果你看到一個*xxx的函數參數聲明(不是函數調用!聲明和調用是兩種不同的含義的),那一定是屬于VAR_POSITIONAL類型的,如同語義,這種類型的參數隻能通過位置POSITIONAL傳參調用,不支援關鍵字KEYWORD傳參,在函數内部,VAR_POSITIONAL類型的參數以一個元祖(tuple)顯示,有一點需要注意的,VAR_POSITIONAL類型可以不傳任何參數調用也不會報錯,而且隻允許存在一個。以下是一個簡單的例子:
def foo(*b):
print(b)
# 不傳參數不會報錯,參數值是一個空元祖
foo() # 結果是 ()
# 可以傳入任意個位置參數調用
foo(1, 2.0, '3', True) #結果是 (1, 2.0, '3', True)
三、KEYWORD_ONLY
第三種是關鍵字參數,這種參數隻會在VAR_POSITIONAL類型參數的後面而且不帶**字首。如同語義,這類參數隻能用關鍵字KEYWORD來傳參,不可以用位置傳參,因為位置傳的參數全讓前面的VAR_POSITIONAL類型參數接收完了,是以KEYWORD_ONLY隻能通過關鍵字才能接收到參數值。以下是一個簡單的例子:
# VAR_POSITIONAL不需要使用時,可以匿名化
def foo(*, c):
pass
# 隻能關鍵字傳參調用
foo(c=1)
四、VAR_KEYWORD
第四種是可變的關鍵字參數,VAR_KEYWORD類型的參數通過**字首來聲明(不是函數調用!聲明和調用是兩種不同的含義的)。如同語義,這種類型的參數隻能通過關鍵字KEYWORD調用,但可以接收任意個關鍵字參數,甚至是0個參數,在函數内部以一個字典(dict)顯示。VAR_KEYWORD類型的參數隻允許有一個,隻允許在函數的最後聲名。以下是簡單的例子:
def foo(**d):
print(d)
# 不傳參數不會報錯,參數值是一個空字典
foo() # 結果是 {}
# 可以傳入任意個關鍵字參數調用
foo(a=1, b=2.0, c='3', d=True) # 結果是 {'d': True, 'c': '3', 'b': 2.0, 'a': 1}
五、POSITIONAL_ONLY
第五種是位置參數,選擇最後說這個,是因為它一點也不重要,屬于python的曆史産物,你無法在高版本的python中建立一個POSITIONAL_ONLY類型的參數,在某種底層的内置函數也許會使用這類型的參數,但我試用inspect子產品也沒法正确識别它的命名,但在Ipython的??幫助下,還是能看到Init signature: dict(self, /, *args, **kwargs)這裡的self就是位置參數POSITIONAL_ONLY了。相信我,你不會需要用到它的,現在python推薦用VAR_POSITIONAL來代替它。下面是一個綜合示例:
import inspect
def foo(a, *b, c, **d):
pass
for name, parame in inspect.signature(foo).parameters.items():
print(name, ': ', parame.kind)
預設參數
VAR類型不允許設定預設參數
POSITIONAL_OR_KEYWORD和KEYWORD_ONLY可以自定義預設參數,而VAR_POSITIONAL和VAR_KEYWORD不允許自定義預設參數的,因為VAR_POSITIONAL的預設參數是tuple()空元祖,而VAR_KEYWORD的預設參數是dict()空字典。如果自定義了預設參數的話,調用函數的時候可以不必傳參,如果預設值是空的話,那就必須傳參數才能調用。
預設參數的位置
POSITIONAL_OR_KEYWORD類型的預設參數一定要放在後面,否則會報錯,KEYWORD_ONLY雖然沒有強制要求,因為都是用關鍵字傳參,誰先誰後都無所謂,但最好還是盡可能地放在後面吧。
預設參數不預設?
預設參數絕對不能設定為可變類型(比如list, dict, set),如果你在函數内改變了預設參數,下次再調用時它就不再是預設值了。
正确的示例:
def foo(p1, p2=2.0, *, k1, k2=None):
a_list = k2 or list()
pass
foo(1, k1='3')