Python *args 與 **kwargs
這篇教學將帶你認識函式參數的進階寫法:*args 接收不定數量的「位置引數」、**kwargs 接收不定數量的「關鍵字引數」。看過 print(1, 2, 3) 可以塞任意個值嗎?背後就是這個機制。
| 寫法 | 接收什麼 | 在函式內的型別 |
|---|---|---|
*args | 任意數量的位置引數 | Tuple |
**kwargs | 任意數量的關鍵字引數 | Dictionary |
(args、kwargs 只是慣例名稱,重點是 * 與 **。)
*args:不定數量的位置引數
def total(*args):
print(type(args), args)
return sum(args)
print(total(1, 2))
print(total(1, 2, 3, 4, 5))
執行輸出:
<class 'tuple'> (1, 2)
3
<class 'tuple'> (1, 2, 3, 4, 5)
15
傳入的值全部被收進一個 Tuple,函式不用管呼叫端傳幾個。
**kwargs:不定數量的關鍵字引數
def build_profile(**kwargs):
print(type(kwargs))
for key, value in kwargs.items():
print(f"{key}: {value}")
build_profile(name="小明", age=25, city="台北")
執行輸出:
<class 'dict'>
name: 小明
age: 25
city: 台北
參數順序規則
混用時順序固定為:一般參數 → *args → 預設參數 → **kwargs:
def demo(a, *args, mode="normal", **kwargs):
print(f"a={a}, args={args}, mode={mode}, kwargs={kwargs}")
demo(1, 2, 3, mode="fast", debug=True)
執行輸出:
a=1, args=(2, 3), mode=fast, kwargs={'debug': True}
呼叫端的 * 與 **:解包
* 與 ** 在「呼叫端」是反過來的用途——把 List/Tuple 或 dict 拆開來傳:
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add(*nums)) # 等同 add(1, 2, 3)
config = {"a": 10, "b": 20, "c": 30}
print(add(**config)) # 等同 add(a=10, b=20, c=30)
執行輸出:
6
60
口訣:定義端的 * 是「收集」,呼叫端的 * 是「拆開」。
實用範例:包裝函式
*args, **kwargs 最常見的實戰用途,是寫「不管原函式長怎樣都能轉傳」的包裝(第 36 篇 Decorator 的基礎):
def log_call(func, *args, **kwargs):
print(f"呼叫 {func.__name__},參數 {args} {kwargs}")
return func(*args, **kwargs)
def add(a, b):
return a + b
print(log_call(add, 3, b=5))
執行輸出:
呼叫 add,參數 (3,) {'b': 5}
8
常見錯誤
1. TypeError: got multiple values for argument
同一個參數同時被位置引數與關鍵字引數指定,例如 demo(1, a=2)。檢查呼叫端是否重複指定。
2. 順序寫錯
def f(**kwargs, *args) 直接 SyntaxError。記住順序:一般 → *args → 預設 → **kwargs。
3. 忘記在呼叫端解包
add(nums) 是把整個 List 當成一個參數(報 TypeError 缺參數),要拆開傳就寫 add(*nums)。
總結
定義端 *args 收位置引數成 Tuple、**kwargs 收關鍵字引數成 dict;呼叫端 * 與 ** 則是把序列與字典拆開來傳;順序是一般 → *args → 預設 → **kwargs。這個機制是之後 Decorator 的基礎。下一篇處理一個常被忽略的主題:變數作用域。