Python 函数参数中的 * 和 ** 是什么意思?
*args 收集多余的位置参数为元组,**kwargs 收集关键字参数为字典;调用时用 * 解包列表、用 ** 解包字典。本文详解星号参数的用法与常见坑。
一句话解释:在函数定义中,*args 表示"接收任意数量的位置参数,打包成元组",**kwargs 表示"接收任意数量的关键字参数,打包成字典";在函数调用中,*列表 把序列解包成位置参数,**字典 把字典解包成关键字参数。
定义时:收集参数
def demo(arg1, *args, **kwargs):
print(arg1) # 必传参数
print(args) # 其余位置参数组成的元组
print(kwargs) # 关键字参数组成的字典
demo(1, 2, 3, 4, keyword1=5, keyword2=6)
# 1
# (2, 3, 4)
# {'keyword1': 5, 'keyword2': 6}
args 和 kwargs 只是约定俗成的名字,写成 *values、**options 也完全合法,星号本身才是语法。
调用时:解包参数
def add(a, b):
return a + b
nums = [1, 2]
opts = {'b': 10}
print(add(*nums)) # 3,等价于 add(1, 2)
print(add(5, **opts)) # 15,等价于 add(5, b=10)
解包写法在包装已有函数、转发参数时特别好用:
def logged_call(func, *args, **kwargs):
logging.info("调用 %s, args=%s, kwargs=%s", func.__name__, args, kwargs)
return func(*args, **kwargs)
参数顺序规则
定义函数时参数顺序必须是:普通参数 → *args → 仅限关键字参数 → **kwargs:
def f(a, b=1, *args, kw_only, **kwargs): ...
kw_only 这种位于 *args 之后的参数,调用时只能用关键字传入,常用于强制调用方写清语义。
观测云对照
用 kwargs 透传日志上下文。 给业务封装统一日志函数时,用 **kwargs 接收结构化字段再合并进 JSON 日志,DataKit 采集后经 Pipeline 解析成可检索字段,排查问题更顺手。
常见问题(FAQ)
Q:* 能单独出现不带变量名吗?
A:可以,def f(a, *, b) 表示 b 是仅限关键字参数,必须写成 f(1, b=2)。
Q:调用时位置解包和关键字解包能混用吗?
A:可以,*args 在前、**kwargs 在后:func(*list, **dict)。
Q:*args 收集的元组能修改吗?
A:元组不可变,但可以在函数内转成 list 处理,不影响外部调用方。