Python怎么定义带参数的函数:位置、默认与可变参数详解

程一诺
程一诺
发布时间:2026-10-20| 7人浏览过
原创

在Python中,定义带参数的函数是通过在 def 语句的小括号内声明变量名实现的。根据传入与接收规则的不同,Python提供了位置参数、默认参数、可变位置参数(*args)和可变关键字参数(**kwargs)四种核心机制。本文将直接展示每种参数的定义语法、求值与匹配原理、混用时的严格顺序要求以及容易踩坑的可变默认对象陷阱,帮助读者掌握严谨高效的函数接口设计方法。

一、函数参数的核心概念与绑定流程

定义函数时小括号中声明的变量被称为形参(Parameter),而调用函数时实际传入的具体数值或对象被称为实参(Argument)。函数执行的本质,是在函数被调用的瞬间,将传入的实参对象依次绑定到形参对应的局部变量名称上,并在函数内部的独立命名空间中运行。

理解参数传递的关键在于掌握Python解释器的参数解析步骤。当一次函数调用发生时,解释器会先计算实参表达式,接着按照严格的规则将实参填入形参槽位中,最后进入函数体执行。

Python怎么定义带参数的函数:位置、默认与可变参数详解
图1:函数调用时实参解析、匹配与局部作用域初始化的完整步骤

二、位置参数:严格按序传递

位置参数(Positional Arguments)是Python中最基础的参数形式。在定义函数时直接书写形参名称即可,调用时必须传入对应数量的实参,解释器严格按照实参出现的先后物理位置与形参逐一匹配。

1. 基本语法与调用示例

def calculate_rectangle_area(width, height):
    return width * height

# 正常调用:按照定义位置依次传入
result = calculate_rectangle_area(5, 10)
print("面积为:", result)

示例输出:

面积为: 50

2. 常见问题与限制条件

位置参数不具备任何默认回退值,因此调用时多传或少传参数都会直接触发 TypeError。例如执行 calculate_rectangle_area(5) 会提示:

TypeError: calculate_rectangle_area() missing 1 required positional argument: 'height'

若参数较多,仅依赖位置容易引起传参顺序混淆,例如将长宽颠倒。此时虽然语法不会报错,但业务逻辑可能出现隐蔽偏差。

三、默认参数:提供可选配置与可变对象避坑

默认参数(Default Arguments)允许在定义函数时使用赋值符号 = 为形参指定默认值。如果调用方未提供该实参,则自动采用预设值;若调用方传入了新实参,则覆盖预设值。

1. 语法规则:位置参数必须在前

在函数签名中,所有没有默认值的形参必须放在带默认值的形参前面。若违反此规则,Python在编译该函数时便会抛出 SyntaxError。

# 正确:必填位置参数在前,可选默认参数在后
def connect_server(host, port=8080, timeout=30):
    print(f"连接到 {host}:{port},超时设为 {timeout} 秒")

# 示例调用
connect_server("192.168.1.100")
connect_server("192.168.1.100", port=9000)

示例输出:

连接到 192.168.1.100:8080,超时设为 30 秒
连接到 192.168.1.100:9000,超时设为 30 秒

2. 致命陷阱:千万不要使用可变对象作为默认值

这是初学者最容易踩中的陷阱之一。在Python中,函数的默认参数只在 def 语句执行时(即模块加载期)求值一次,而不是在每次函数被调用时重新创建。

如果使用列表(list)、字典(dict)等可变对象作为默认值,所有未显式传参的调用都将共享内存中的同一个对象实例,导致前一次调用的修改在后续调用中持续累积。

Python怎么定义带参数的函数:位置、默认与可变参数详解
图2:默认参数在编译期求值机制造成的共享陷阱与标准修复方案

四、可变参数:处理不确定数量的输入

在编写工具函数、包装器(装饰器)或数学计算函数时,往往无法预知调用者会传入多少个参数。Python提供了 *args 与 **kwargs 两种语法,用于接收任意数量的实参。

1. 可变位置参数:*args 打包为元组

在形参名前加上单个星号 *,解释器会将调用时传入的所有未被前面位置参数认领的实参,打包成一个元组(tuple)存入该变量。

def calculate_sum(*numbers):
    total = 0
    for n in numbers:
        total += n
    return total

print("无参数结果:", calculate_sum())
print("两个参数结果:", calculate_sum(10, 20))
print("多个参数结果:", calculate_sum(1, 2, 3, 4, 5))

示例输出:

无参数结果: 0
两个参数结果: 30
多个参数结果: 15

2. 可变关键字参数:**kwargs 打包为字典

在形参名前加上双星号 **,解释器会将所有未匹配的 key=value 键值对实参,打包为一个字典(dict)存入该变量。

def build_user_profile(user_id, **attributes):
    profile = {"id": user_id}
    profile.update(attributes)
    return profile

user = build_user_profile(1001, name="Alice", department="DevOps", level=3)
print("用户档案:", user)

示例输出:

用户档案: {'id': 1001, 'name': 'Alice', 'department': 'DevOps', 'level': 3}
Python怎么定义带参数的函数:位置、默认与可变参数详解
图3:*args 与 **kwargs 在调用与透传过程中的打包/解包行为

五、组合参数:必须遵循的定义顺序

在实际工程中,常常需要在一个函数内同时使用位置参数、默认参数、*args、命名关键字参数和 **kwargs。Python语法对此有非常明确且唯一的排列顺序限制:

def complex_func(pos1, pos2, default_arg=10, *args, kw_only=50, **kwargs):
    pass

如果不按照该顺序编写,解释器会在定义阶段抛出语法错误,或者在调用时产生歧义。

参数分类 排列顺序 语法标识 解析逻辑与作用
位置参数 第 1 位 arg 调用必须传值,按位置优先填入。
默认参数 第 2 位 arg=value 提供预设初值,如果位置参数传完还有多余则按序填入,否则取默认值。
可变位置参数 第 3 位 *args 接收前面位置和默认参数填满后所有剩余的位置实参,存入元组。
命名关键字参数 第 4 位 *, kw_only 在 *args 之后的参数,调用时必须以 key=value 形式明确显式传参。
可变关键字参数 第 5 位 **kwargs 必须位于函数签名的最末尾,接收所有未被显式捕获的关键字实参。
Python怎么定义带参数的函数:位置、默认与可变参数详解
图4:从左到右5类参数类型的标准声明顺序与语法约束

六、常见调用报错排查清单

1. SyntaxError: non-default argument follows default argument

触发原因:函数定义时,带默认值的形参出现在了无默认值的普通形参前面。
解决方法:调整形参顺序,将无默认值的必填参数全部移至最左侧。

2. TypeError: ... got multiple values for argument '...'

触发原因:同一个形参既通过位置传了值,又通过关键字形式再次指定了值。

def set_profile(name, age):
    pass

# 错误调用:name既获得了位置实参 "Tom",又被关键字实参赋值
set_profile("Tom", 20, name="Jerry")

解决方法:确认调用语句中的位置实参与关键字实参没有指向同一参数槽位。

3. TypeError: ... got an unexpected keyword argument '...'

触发原因:传入了一个函数签名中未声明的关键字实参,且函数没有声明 **kwargs 用于接收多余参数。
解决方法:检查参数名拼写是否与函数定义一致;若该函数确实需要扩展接收外部动态参数,在形参末尾增加 **kwargs。

七、总结与最佳实践建议

在Python中设计带参数的函数时,建议遵循以下实用原则:

  • 必填优先,可选在后:核心业务数据通过位置参数强制传入,配置项通过默认参数设定,保证接口调用直观简洁。
  • 坚守不可变默认值:默认参数永远首选 None、整数或字符串;遇列表、字典时务必在函数体内使用 if x is None: x = [] 动态初始化。
  • 谨慎泛用 *args 与 **kwargs:虽然它们提供了极大的灵活性,但会削弱代码的可读性与静态类型检查工具的提示能力。除编写中间件、装饰器或转发接口外,尽量显式声明具体参数名称。
  • 合理利用强制关键字传参(*):对于布尔型配置开关(如 debug=True、dry_run=False),置于 * 之后能够强制调用方写出参数名称,避免类似 func(1, 2, True, False) 这种意义不明的“神秘布尔值”传参。
相关标签:

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

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 算法库。