python参数类型_Python 参数类型和参数匹配模型
Python 方法的參數種類有很多,而不是通常語言定義的那樣, Python 方法的傳參能力要比想象的強大很多。很多初學者可能對一些庫中帶 * 帶 ** 的參數類型非常奇怪,但是其實這些語法正是保證 Python 方法傳參強大的重要因素。
First Thing
首先要聲明 argument 和 parameter 的區別,很多時候這兩個單詞被直接翻譯為參數更導致了很多人無法區分,argument 是調用方發起的稱呼,parameter 是定義方法時使用
def foo(a, b): # <- a and b are "parameters" or "formal arguments"
pass
foo(1, 2) # <- 1 and 2 are arguments to foo, that match a and b
參數類型
在討論參數類型之前,先來看一個例子
def bar(a, # <- this parameter is a normal python parameter
b=1, # <- this is a parameter with a default value
*, # <- all parameters after this are keyword only
c=2, # <- keyword only argument with default value
d): # <- keyword only argument without default value
pass
這是一個典型的方法定義,其中包括了一些類型,但是還不全面。
Python 的參數類型:
Positionals: matched from left to right 很多教程都叫做:位置參數
顧名思義,就是從左往右匹配,比如 def foo(a, b): pass 傳參的時候就必須 foo(1,'a') 按照位置傳
Keywords: matched by argument name
也就是傳參時需要指定關鍵詞 (name=value) 這樣的形式傳,比如定義 def func(name=value):pass 然后調用 func(name=value)
Defaults: specify values for arguments that aren’t passed
可以給某些參數默認值,如果不傳這些參數則使用默認值,這些可選參數傳值時也需要 name=value
Varargs collecting: collect arbitrarily many positional or keyword arguments
方法可以使用帶 * 或者 ** 的參數來收集任意長度的參數,定義方法時 def func(*name) 用來收集剩下的位置參數然后保存到 tuple 中,定義方法 def func(**name) 將收集所有的 keyword arguments 然后作為 dictionary
Varargs unpacking: pass arbitrarily many positional or keyword arguments
調用者可以使用 * 方式來 unpack 參數集合,比如 func(*sequence) 調用者將 sequence 的所有對象一個個按照順序傳入(作為單獨的 positional arguments), func(**dict) 調用者將 dict 中的所有 key/value 以單獨的關鍵詞參數傳入 (keyword arguments)
Keyword-only arguments: arguments that must be passed by name
In Python 3.0 以后引入,可以指定必須 name=value 傳遞
總而言之,上面定義的參數類型模型,讓 Python 能夠決定方法需要傳遞多少參數,通常情況下位置參數調用者必須顯示指定,而如果定義了默認參數調用者往往可以省去,而如果定義了 * 參數,則表示調用者可以傳任意數量的參數。
順序
方法定義和方法調用都要遵循一定的順序:
方法調用者,參數列表需要按照如下順序:positional arguments(value) -> keyword arguments(name=value) -> *sequence -> **dict
而方法定義時,參數定義需要按照: normal arguments(name), 跟著 default arguments(name=value), -> *name -> name or name=value keyword-only arguments -> **name
在定義和調用時, **arg 如果定義都必須在最后出現,如果不按照順序使用,會給出語法錯誤。 Python 內部按照下面的步驟來匹配參數列表:
先按照 positional arguments 來賦值,對于任何 positional arguments:
嘗試將 argument 綁定到第一個沒有填充的 parameter slot,如果 slot 不是 vararg slot,標記 slot 為 filled 。
如果下一個 unfilled slot 是一個 vararg slot,并且沒有 name 那么報錯
否則(下一個 unfilled slot 是一個 vararg slot),所有剩下的 non-keyword arguments 都傳給 vararg slot。
再按照 keyword arguments 來賦值任何匹配的參數
如果 parameters 中存在 name 和 keyword 匹配的參數,在將 argument value 賦值給 parameter slot. 如果 parameter slot 已經 filled,報錯
否則,如果有 keyword dictionary argument, argument 就添加到存在的 dictionary,如果已經存在同名 key,則報錯
否則,如果沒有 keyword dictionary, 并且沒有匹配的 named parameters , 報錯
將剩余沒有 keyword 的參數賦值給 *name 元組
將剩余的 keyword 參數賦值給 **name 字典
最后將默認值賦值給沒有傳入的參數
如果 vararg slot 還沒有填充,將空的 tuple 賦值給他
對于剩下的空的 slot,如果有默認值則填充,如果沒有默認值,則報錯
在這些之后,Python 會檢查每個參數都已經有且僅有一個值,如果不是將拋出錯誤。一旦匹配完成,Python 就將傳入的對象賦值給參數名。
在這些都理清楚之后 Python 3.0 還有一個 keyword-only arguments 似乎還要費些筆墨。
Python 3.0 Keyword-Only Arguments
Python 3.0 總結了定義方法時參數列表的順序,允許我們使用 keyword-only arguments —- 這類參數只能通過 keyword 傳入,永遠不會使用 positional argument 來填充。當我們既想要方法處理任意數量的 arguments 并且也可選的接受一些 configuration 選項時。
句法上, keyword-only arguments 類似于 named arguments,但是出現在 *args 后面。所有這類 argument 都必須在調用時使用 keyword 形式傳入。
>>> def kwonly(a, *b, c):
print(a, b, c)
>>> kwonly(1, 2, c=3)
1 (2,) 3
>>> kwonly(a=1, c=3)
1 () 3
>>> kwonly(1,2,3)
TypeError: kwonly() needs keyword-only argument c
這里 *b 如果不需要任意長度可以簡寫為 *
>>> def kwonly(a, *, b, c):
print(a, b, c)
>>> kwonly(1, c=3, b=2)
1 2 3
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1,2,3)
TypeError: kwonly() takes exactly 1 positional argument (3 given)
>>> kwonly(1)
TypeError: kwonly() needs keyword-only argument b
在 * 之后依然可以使用帶默認值的參數,b,c 如果被使用到則必須使用 keyword
>>> def kwonly(a, *, b='spam', c='ham'):
...
print(a, b, c)
...
>>> kwonly(1)
1 spam ham
>>> kwonly(1, c=3)
1 spam 3
>>> kwonly(a=1)
1 spam ham
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1, 2)
TypeError: kwonly() takes exactly 1 positional argument (2 given)
如果 keyword-only 參數沒有默認值,則在調用時必須傳入
在調用時,keyword-only 被傳入時,必須要在 **args 之前
>>> def f(a, *b, c=6, **d): print(a, b, c, d)
>>> f(1, *(2, 3), **dict(x=4, y=5))
1 (2, 3) 6 {'y': 5, 'x': 4}
>>> f(1, *(2, 3), **dict(x=4, y=5), c=7)
SyntaxError: invalid syntax
>>> f(1, *(2, 3), c=7, **dict(x=4, y=5))
1 (2, 3) 7 {'y': 5, 'x': 4}
>>> f(1, c=7, *(2, 3), **dict(x=4, y=5))
1 (2, 3) 7 {'y': 5, 'x': 4}
>>> f(1, *(2, 3), **dict(x=4, y=5, c=7))
1 (2, 3) 7 {'y': 5, 'x': 4}
為什么要有 keyword-only arguments ,簡單的來說,就是想讓方法支持任意的 positional arguments 并且讓 configuration 選項作為 keyword 傳入。
比如想要實現一個函數,處理傳入的一組對象,并且有一個開關用來指定處理完成之后是否通知
process(X, Y, Z)
process(X, Y, notify=True)
如果沒有 keyword-only arguments,我們可能需要同時使用 *args 和 **args 并且人工的從 keywords 中獲取 notify 。使用 keyword-only 可以節省很多
def process(*args, notify=False): ...
reference
總結
以上是生活随笔為你收集整理的python参数类型_Python 参数类型和参数匹配模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鸿蒙系统不是安卓!“鸿蒙之父”王成录被禁
- 下一篇: 微软 Win11 Dev 预览版 Bui