在查看一些 Python 文件時常會看到參數中出現 / 與 *, 一開始沒有太注意, 後來才發現原來是有意義的, 簡單的來說:
-
/:表示出現在它前面的參數只能是以對應位置傳入資料, 不能用指名的方式。 -
*:表示出現在它之後的參數只能用指名的方式傳入資料。
這樣講可能有點抽象, 以底下這個函式為例:
>>> def foo(n, /, a, b=2, *, c):
... print(f'{n=}')
... print(f'{a=}')
... print(f'{b=}')
... print(f'{c=}')
代表:
-
n必須是位置引數 -
a可以是位置引數或是指名引數 -
b可以是位置引數或是指名引數 -
c必須是指名引數
在叫用 foo 的時候就必須要符合以上規定, 以下都是不符合規定的狀況:
>>> foo(n=10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got some positional-only arguments passed as keyword arguments: 'n'
由於 n 只能以位置參數傳入資料, 所以錯誤訊息明白告訴你把只能依照位置傳入的引數當指名引數用了。
>>> foo(10, 20)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required keyword-only argument: 'c'
這樣 n 是 10, a 是 20, b 是預設的 2, 但是 c 沒有值, 所以也不行。
>>> foo(10, 20, 30)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required keyword-only argument: 'c'
由於 c 必須以指名方式傳入資料, 所以即使多加了一項資料, 也不符合規定。
>>> foo(10, 20, c=30)
n=10
a=20
b=2
c=30
這樣就對了。注意到由於以位置傳資料的引數必須出現在定名稱傳資料的參數之前, 所以也不能這樣叫用:
>>> foo(10, a=20, 25, c=30)
否則 b 變成是以位置傳入資料, 但是卻又出現在指名傳資料的 a 後面了。
不定個數的引數
你還可以和不定個數的引數形式合併使用,例如若把剛剛的函式修改如下,在 * 後面加上參數名稱:
>>> def foo(n, /, b=2, *pos, c, **args):
... print(f'{n=}')
... print(f'{b=}')
... print(f'{pos=}')
... print(f'{c=}')
... print(f'{args=}')
這表示:
-
n是位置參數。 -
b可以是位置或是指名參數。 -
pos之後出現的都是指名參數,pos本身會是一個序組(tuple),存放b之後出現的所有位置引數。 -
c是指名參數。 -
args會是一個字典,存放所有未列在參數清單中的指名引數。
以下是不同的叫用案例:
>>> foo(2, c=3)
n=2
b=2
pos=()
c=3
args={}
由於只有一個位置引數,所以會對應到 n,而 b 就會得到預設值 2,之後因為沒有其他的位置引數,所以 pos 是一個空的序組;同理,由於 c 之後也沒有其他的指名引數,所以args 是空的字典。如果是這樣叫用:
>>> foo(2, 3, 4, c=3)
n=2
b=3
pos=(4,)
c=3
args={}
位置引數有三個,個別對應到 n 和 b 之後,剩下 4,所以 pos 就是含有一項資料的序組,但 args 仍然是空的字典。如果改成以下的叫用方式:
>>> foo(2, 3, 4, c=3, d=5, e=6)
n=2
b=3
pos=(4,)
c=3
args={'d': 5, 'e': 6}
由於 c 之後還有其他指名引數,所以 args 就會是包含這些指名引數的字典了。
要注意的是,如果 b 傳入指名引數,由於指名引數一定要出現在位置引數之後,b 後面就不能再傳入位置引數,例如:
>>> foo(2, b=3, 4, c=3, d=5, e=6)
就會出現錯誤:
# python test.py
File "C:\python\test.py", line 8
foo(2, b=3, 4, c=3, d=5, e=6)
^
SyntaxError: positional argument follows keyword argument
小結
你自己不一定會這樣設定參數, 但是許多套件內的模組為了傳遞資料的彈性, 又必須讓你知道傳遞資料時的規範, 都會使用這樣的方式設定參數, 瞭解它們的意義才能看懂文件, 運用正確的方式叫用函式或方法。
Top comments (0)