Python函数参数解包详解:*与**的调用、定义及常见误区

慢慢来
慢慢来
发布时间:2026-10-10| 3人浏览过
原创

本文详细讲解 Python 中单星号 * 与双星号 ** 在函数调用和定义中的核心作用。通过位置参数与关键字参数的展开机制、容器合并技巧、强制关键字参数规则以及常见类型错误排查,帮助开发者掌握 Python 高级传参语法,提升代码简洁性与可维护性。

核心概念:参数解包的两种形态

在 Python 函数调用时,* 和 ** 用于将容器内的元素拆解并传递给目标函数。单星号针对序列对象(如列表、元组),生成位置参数;双星号针对字典对象,生成关键字参数。

符号解包对象调用时变为
*列表、元组等序列位置参数 func(1, 2, 3)
**字典关键字参数 func(a=1, b=2)

记忆口诀:一个星号管位置,两个星号管关键字。

单星号 *:展开序列与收集多余参数

调用时:将列表或元组拆分为位置参数

def greet(name, age, city):
    print(f"{name}, {age}岁, 来自{city}")

args = ["Alice", 20, "Beijing"]
greet(*args)  # 等价于 greet("Alice", 20, "Beijing")

*args 会按顺序将容器元素匹配到函数的位置形参上。元组操作方式完全一致:

point = (10, 20)
def draw(x, y):
    print(x, y)
draw(*point)  # 输出: 10 20

混用普通参数时的排列规则

在函数调用中,* 解包段通常位于其他位置参数之后,且插入位置会直接改变参数匹配顺序。

# 正确写法
foo(1, *[2, 3])       # ✅ 等价于 foo(1, 2, 3)
# 错误写法示例
# foo(*[1, 2], 3)     # ❌ SyntaxError: 星号表达式不允许出现在该位置

定义时:使用 *args 收集冗余位置参数

def foo(*args):
    print(args)
    print(type(args))

foo(1, 2, 3)
# 输出:
# (1, 2, 3)
# <class 'tuple'>

当传入的参数数量超过明确定义的形参时,未被捕获的值会自动打包为元组赋予 *args。

双星号 **:字典展开与关键字参数收集

调用时:将字典键值对映射为关键字参数

def greet(name, age):
    print(f"name={name}, age={age}")

info = {"name": "Alice", "age": 20}
greet(**info)  # 等价于 greet(name="Alice", age=20)

字典的 key 必须严格对应函数的形参名,且必须是合法的 Python 标识符。

定义时:使用 **kwargs 收集冗余关键字参数

def foo(**kwargs):
    print(kwargs)

foo(a=1, b=2)  # 输出: {'a': 1, 'b': 2}

工程实战中的应用链

在配置类实例化或数据过滤场景中,常结合字典推导式使用:

values = {"max_step_num": 5, "locale": "", "debug": False}
# 过滤空值后解包传给配置类
return cls(**{k: v for k, v in values.items() if v})
  1. 字典推导式筛选出有效配置项
  2. ** 展开为 Configuration(max_step_num=5, debug=False)
  3. 未提供的字段由类的默认值自动补全

混合使用与高级特性

调用时同时解包位置与关键字参数

pos = [3, 4]
kw = {"x": 10, "y": 20}

def foo(a, b, c, x, y):
    print(a, b, c, x, y)

foo(1, 2, *pos, **kw)  # 等价于 foo(1, 2, 3, 4, x=10, y=20)

调用时的固定执行顺序为:显式位置参数 → *解包 → 显式关键字参数 → **解包。

强制关键字参数(Python 3+)

在参数列表中单独放置一个 *,其后的所有形参必须通过关键字形式传递,否则触发 SyntaxError:

def connect(host, port, *, timeout=30, ssl=True):
    pass

connect("localhost", 3306, timeout=60)  # ✅
# connect("localhost", 3306, 60)        # ❌ timeout 必须显式声明

该机制与 @dataclass(kw_only=True) 的设计哲学一致,强制要求命名传参以提升接口清晰度。

容器合并与高阶转发技巧

列表与元组合并

a = [1, 2]
b = [3, 4]
c = [*a, *b]           # 结果: [1, 2, 3, 4]

字典合并与覆盖规则

a = {"x": 1}
b = {"y": 2}
c = {**a, **b}         # 结果: {"x": 1, "y": 2}

b = {"x": 99}
{**a, **b}             # 结果: {"x": 99} (后者优先覆盖)

装饰器与包装器参数转发

def wrapper(*args, **kwargs):
    print("调用前准备...")
    result = original_func(*args, **kwargs)  # 原样透传
    print("调用结束清理...")
    return result

常见报错与排错指南

参数数量不匹配

def foo(a, b): pass
foo(*[1, 2, 3])          # TypeError: too many positional arguments
foo(**{"a": 1})          # TypeError: missing 1 required positional argument: 'b'

关键字名称非法或重复

foo(**{"max-step": 5})   # KeyError: key含非字母字符,无法转为参数名
foo(1, b=2, *[3])        # TypeError: multiple values for argument 'b'
foo(1, **{"a": 99})      # TypeError: got multiple values for argument 'a'

运算符上下文混淆

注意 * 在不同语法域的含义差异:在表达式中是乘法运算(如 2 * 3 → 6),仅在函数调用的实参位置或函数定义的形参表头中,才表示解包或收集。

总结

foo(*[1, 2, 3])              # 位置参数展开: foo(1, 2, 3)
foo(**{"a": 1, "b": 2})      # 关键字参数展开: foo(a=1, b=2)
cls(**{"max_step_num": 5})   # 配置类注入: Configuration(max_step_num=5)
场景* 的行为** 的行为
调用传参将序列拆分为位置参数将字典拆分为关键字参数
定义接收*args 收拢为 tuple**kwargs 收拢为 dict

以上就是Python利用*与**进行解包的详细内容,更多关于Python函数参数传递的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。