*args 和 让函数接受的参数。 将额外的参数收集到元组中; 将额外的参数收集到字典中。(名字是约定俗成的 — 和 才是关键。)
**kwargs*args**kwargs***def total(*args): # collects all positional args into a tuple
print(args) # e.g. (1, 2, 3)
return sum(args)
total(1, 2, 3) # 6
total(1, 2, 3, 4, 5) # 15 — any number of args
def configure(**kwargs): # collects keyword args into a dict
print(kwargs) # e.g. {"host": "localhost", "port": 8080}
for key, value in kwargs.items():
print(f"{key} = {value}")
configure(host="localhost", port=8080, debug=True)
def func(a, b, *args, **kwargs):
# a, b → required positional
# args → extra positional (tuple)
# kwargs → extra keyword (dict)
...
func(1, 2, 3, 4, x=5, y=6)
# a=1, b=2, args=(3, 4), kwargs={"x": 5, "y": 6}
必需的顺序是:常规参数,然后 *args,然后 **kwargs。
# `*` and `**` also UNPACK collections INTO arguments at the call site
numbers = [1, 2, 3]
total(*numbers) # same as total(1, 2, 3)
settings = {"host": "x", "port": 80}
configure(**settings) # same as configure(host="x", port=80)
相同的语法将列表/字典解包为位置/关键字参数 — 对于转发参数很方便。
def wrapper(*args, **kwargs):
# accept ANY arguments and pass them through unchanged
return original_func(*args, **kwargs)
这种传递模式是装饰器和包装函数如何处理任意函数签名的方式。
*args/**kwargs 实现了灵活的函数签名,可以接受任意数量的参数 — 这对于编写通用工具、包装器,特别是装饰器(必须通过 *args, **kwargs 包装未知签名的函数)是必不可少的。
解包方向(*list、**dict)同样适用于转发或展开参数。
理解收集和解包两个方向对于编写可重用的、通用的 Python 代码,以及阅读许多依赖这些特性的库 API 和装饰器是关键。