在 Python 中,函数形参与实参的对应方式决定外部数据如何进入函数体。除位置实参与关键字实参外,还可为形参指定默认值,并用 *args、**kwargs 接收不定数量的实参;调用侧亦可用 *、** 对序列或字典解包传参。若默认参数使用可变对象,或关键字实参与位置实参顺序不当,可能产生与预期不符的结果。本节按传参形态说明定义与调用规则。
位置实参与关键字实参
同一组形参既可按定义顺序传入位置实参,也可按名称传入关键字实参:
def describe(name, age):
print(f"{name} 今年 {age} 岁")
describe("小明", 20)
describe(age=18, name="小红")位置参数
位置实参按从左到右的顺序依次绑定形参;顺序错误则绑定关系错误:
def greet(first, last):
print(f"Hi {first} {last}")
greet("Tom", "Smith")关键字参数
写成 形参名=值 后,不再依赖左右顺序。若与位置实参混用,位置实参须位于关键字实参之前:
greet(last="Smith", first="Tom")
# greet(last="Smith", "Tom") # SyntaxError:位置实参不能跟在关键字实参之后
默认参数
形参指定默认值后,调用可省略该实参;显式传入时覆盖默认值。默认值在函数定义时求值一次,故可变对象作默认值会在多次调用间共享,见文末常见错误:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Tom")
greet("Tom", "Hi")*args:不定长位置参数
形参前加单个 * 时,额外位置实参收为元组;若无额外位置实参,则为空元组:
def total(*args):
print(args)
return sum(args)
print(total(1, 2, 3)) # 打印 (1, 2, 3),返回 6
print(total()) # 打印 (),返回 0**kwargs:不定长关键字参数
**kwargs 将额外关键字实参收为字典,键为参数名,值为传入对象:
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key} = {value}")
print_info(name="Tom", age=18, city="Beijing")输出:
name = Tom
age = 18
city = Beijing混合定义时的顺序
同一条 def 可组合多种形参。常见顺序为:普通形参、*args、仅允许关键字传入的形参(可带默认值)、**kwargs。下例中 b=10 位于 *args 之后,调用时须以关键字传入 b:
def mixed(a, *args, b=10, **kwargs):
print(a, args, b, kwargs)
mixed(1, 2, 3, b=99, x=1, y=2)
# 1 (2, 3) 99 {'x': 1, 'y': 2}调用时解包
若实参已存在于列表、元组或字典,可在调用处使用 * 或 ** 展开。序列按位置展开,字典按键名与形参对齐:
def add3(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add3(*nums))
info = {"a": 1, "b": 2, "c": 3}
print(add3(**info))常见错误
- 默认参数为
[]、{}等可变对象时,多次调用共享同一对象;应使用def f(x=None)并在函数内if x is None: x = []。 - 关键字实参之后不能再写位置实参,否则语法错误。
*args/**kwargs仅为约定名称,机制不依赖该名称,但团队内宜统一以便阅读。
本节说明了 Python 中各类实参与形参的对应关系及解包调用。下一节介绍lambda 表达式:单行匿名函数及其与 sorted、filter、map 的配合。