当前位置:首页>python>Python 函数参数:把“值”准确交给“名字”

Python 函数参数:把“值”准确交给“名字”

  • 2026-10-11 05:41:44
Python 函数参数:把“值”准确交给“名字”

Python 的函数参数看起来只是 def func(a, b):这种语法。真正重要的是:调用函数时,Python 会把你传入的值绑定到函数签名里的名字。理解这件事,位置参数、关键字参数、默认参数、*args、**kwargs都会变得清楚。

1. 先区分“参数”和“实参”

参数是函数定义里的名字,实参是调用函数时传进去的值。

def greet(name, message):    print(f"{name}: {message}")greet("Yves", "Hello")

这里 name和 message是参数,"Yves"和 "Hello"是实参。函数执行时,Python 会得到两个局部变量:

name = "Yves"message = "Hello"

2. 位置参数:按顺序绑定

位置参数靠顺序决定谁是谁。

def power(base, exponent):    return base ** exponentpower(2, 3)  # 8

2绑定给 base,3绑定给 exponent。这种写法短,但当参数很多时,可读性会下降。

3. 关键字参数:按名字绑定

关键字参数靠名字决定绑定关系,顺序可以调整。

power(exponent=3, base=2)  # 8

这类写法适合配置型函数:

def connect(host, port, timeout):    ...connect(host="localhost", port=5432, timeout=3)

调用者一眼能看到每个值的含义。

4. 默认参数:给参数一个备用值

默认参数让调用者少传一些值。

def create_user(name, role="member", active=True):    return {"name": name, "role": role, "active": active}create_user("Tom")create_user("Alice", role="admin")

默认参数有一个经典陷阱:可变对象会在函数定义时创建一次,后续调用共享同一个对象。

def add_item(item, items=[]):    items.append(item)    return itemsadd_item("a")  # ["a"]add_item("b")  # ["a", "b"]

更稳的写法是用 None做哨兵值:

def add_item(item, items=None):    if items is None:        items = []    items.append(item)    return items

5. *args:收集多余的位置参数

*args会把多余的位置实参收集成元组。

def total(*numbers):    return sum(numbers)total(1, 2, 3, 4)  # 10

常见场景是包装函数:

def log_call(fn, *args):    print("calling", fn.__name__)    return fn(*args)log_call(max, 3, 9, 1)  # 9

这里 fn(*args)是参数解包,把元组重新展开成位置参数。

6. **kwargs:收集多余的关键字参数

**kwargs会把多余的关键字实参收集成字典。

def build_profile(name, **extra):    return {"name": name, **extra}build_profile("Yves", role="dev", city="Shanghai")

结果是:

{"name": "Yves", "role": "dev", "city": "Shanghai"}

它适合做扩展点,但要控制边界。公共 API 里滥用 **kwargs会让调用者不知道到底支持哪些选项。

7. 仅限关键字参数:把配置写清楚

*后面的参数只能用关键字传递。

def export(data, *, format="json", pretty=False):    ...export(records, format="csv", pretty=True)

这能避免调用者写出难读的代码:

export(records, "csv", True)

配置项越多,越应该考虑关键字专用参数。

8. 仅限位置参数:用 /限制名字

/左边的参数只能按位置传递。

def divmod_like(a, b, /):    return a // b, a % bdivmod_like(10, 3)

这种写法在普通业务代码中少见,但在标准库和底层 API 里有价值。它允许函数作者未来调整参数名,同时减少调用者依赖内部命名。

9. 完整顺序:一条规则记住所有类型

Python 函数参数的推荐顺序是:

def func(pos_only, /, pos_or_kw, default=0, *args, kw_only, **kwargs):    ...

也可以拆开看:

位置专用参数 → 普通参数 → 默认参数 → *args → 关键字专用参数 → **kwargs

实际代码里很少需要一次写全。大多数业务函数只需要普通参数、默认参数、关键字专用参数。

10. 实战建议

写函数时可以按这个原则判断:

参数少、含义明确时,用位置参数。

参数含义容易混淆时,用关键字参数。

配置项有默认行为时,用默认参数。

包装函数或透传调用时,用 *args和 **kwargs。

公共 API 的配置项,优先做成关键字专用参数。

可变默认值用 None初始化,减少共享状态风险。

11. 一个综合例子

def request(    method,    url,    /,    *,    timeout=5,    headers=None,    retries=0,    **options,):    headers = headers or {}    print(method, url, timeout, headers, retries, options)request(    "GET",    "https://example.com",    timeout=10,    headers={"Accept": "application/json"},    retries=2,    verify_ssl=True,)

这个签名表达了清晰的约束:

method和 url是核心输入,按位置传。

timeout、headers、retries是配置,必须写名字。

额外选项进入 options,给未来扩展留空间。

总结

Python 函数参数的核心问题只有一个:调用时的值如何绑定到函数内部的名字。位置参数解决顺序,关键字参数解决可读性,默认参数解决常用值,*args和 **kwargs解决弹性,/和 *解决 API 边界。

把这些工具组合好,函数签名本身就会变成文档。调用者少猜,维护者少解释。

最新文章

随机文章