1. 引言
Python 作為一種動態類型語言(Dynamically Typed Language),提供了高度靈活的函數形式參數(Formal Parameters)定義方式。不同於許多靜態類型語言對函數參數數量與類型的嚴格約束,Python 允許函數在運行時接受不定數量的參數,並基於內部模型自動完成參數綁定(Argument Binding)。
其中,*args 與 **kwargs 是 Python 函數參數體系的核心特性,用於處理變長參數與構建開放式、可擴展的函數接口。它們在標準庫設計(如 print()、logging、matplotlib)與各類框架(如 Django、Flask、FastAPI)中被廣泛使用。
2. 語法機制
*args:可變位置參數(Variable Positional Arguments)
帶有前綴*的形式參數用於捕獲調用時傳入的所有 額外位置實參(positional arguments)。
語法格式如下:
def function_name(*args):
pass
args接收一個 tuple 類型對象。- 參數名稱可以自定義,但根據 PEP 8 規範一般使用
args。
示例:
def f(*args):
print(args)
f(10, 20, 30)
# 輸出: (10, 20, 30)
**kwargs:可變關鍵字參數(Variable Keyword Arguments)
帶有前綴**的形式參數用於捕獲所有未被其它具名參數綁定的 額外關鍵字實參(keyword arguments)。
def function_name(**kwargs):
pass
kwargs接收一個 dict[str, Any] 對象。- 字典鍵必須為字符串,這是 Python 語法層面保證的約束。
示例:
def f(**kwargs):
print(kwargs)
f(a=1, b=2)
# 輸出: {'a': 1, 'b': 2}
- 參數定義順序(Parameter Ordering Rules)
根據 Python 語法規範(參考 PEP 3102),函數參數必須遵循以下順序:
def func(
positional_parameters,
default_parameters,
*args,
keyword_only_parameters,
**kwargs
):
...
錯誤順序將導致解析階段報錯。
3. 類型特徵
*args的類型語義
*args的內部類型始終為:
tuple[Any, ...]
無論傳入多少實參均滿足此結構。
**kwargs的類型語義
**kwargs的類型固定為:
dict[str, Any]
其中:
- 鍵(key)類型必須為
str(由語法生成)。 - 值(value)類型不受限制。
- 類型提示(Type Hinting)規範
基於 PEP 484 與 PEP 612,官方推薦的註解方式如下:
def func(*args: int, **kwargs: str) -> None:
...
其語義為:
args是 “tuple of int”kwargs是 “dict[str, str]”
進一步形式化表示:
args: tuple[int, ...]
kwargs: dict[str, str]
4. 運行機制與內部模型
- 參數打包(Packing)過程
在調用函數時,例如:
func(1, 2, 3, x=10, y=20)
Python 的內部參數綁定流程可概括為:
- 位置參數依次與具名位置形參綁定。
- 多餘的位置參數被收集並構成一個
tuple,綁定給*args。 - 關鍵字參數與具名關鍵字形參匹配。
- 多餘的關鍵字參數構成一個
dict,綁定給**kwargs。
- 參數解包(Unpacking)過程
使用*與**可在調用時進行解包:
data = (1, 2)
options = {"x": 10}
func(*data, **options)
內部等價於:
func(1, 2, x=10)
這為 Python 設計動態 API 提供關鍵能力。
5. 設計初衷
- 構建高度動態的函數接口
Python 強調“鴨子類型”(Duck Typing)與運行時靈活性,因而需要允許函數接受:
- 任意數量的位置參數
- 任意數量的關鍵字參數
這對框架設計尤為重要,如:
- Flask 的視圖函數
- Django 的類視圖方法
- Numpy 與 Pandas 的構造與操作函數
這些函數都無法預先預測用户將提供哪些參數。
- 代理與轉發
構建代理函數或裝飾器時,必須保證參數不丟失:
def wrapper(*args, **kwargs):
return target(*args, **kwargs)
這是裝飾器設計模式在 Python 中得以實現的基石。
- 保證繼承體系中的兼容性
在面向對象繼承體系中,子類方法經常需要保持對父類接口的兼容性:
class Base:
def run(self, *args, **kwargs):
pass
子類可以擴展參數而不會破壞方法簽名。
- 構建可擴展的配置接口
科學計算、繪圖庫等大量採用**kwargs作為可擴展配置入口,例如:
plt.plot(..., linewidth=2, label="test", color="red")
這是一種開放 API(Open API)的典型設計方式。
6. 使用注意事項
- 避免濫用
不必要地使用*args和**kwargs可能損害可讀性,建議僅在需要提供擴展性或構建框架級 API 時使用。 args是不可變 tuple
如需調整其內容需顯式轉換:
args = list(args)
- 關鍵字參數鍵必須是字符串
以下寫法為非法:
func(**{1: "invalid"}) # SyntaxError
- 注意函數簽名的清晰可讀性
在庫開發中,建議保留基礎參數並將可擴展部分交由**kwargs處理:
def connect(host: str, port: int, **options: Any) -> None:
...
7. 總結
*args 與 **kwargs 是 Python 函數機制中最具動態性與擴展能力的元素,它們構成了:
- Python 高度靈活的參數調用模型
- 框架與庫設計的通用接口機制
- 裝飾器與代理模式的基礎設施
通過理解其語法、類型結構與底層動因,開發者可以更有效地構建兼具簡潔性與可擴展性的函數接口,從而充分發揮 Python 動態語言的優勢。