Skip to content

15|函数参数

函数通过参数接收外部数据。Python 的参数机制灵活:位置传参、关键字传参、默认值、可变数量参数——理解这些机制,才能写出既易用又不易出错的函数接口。

一、位置参数

按照定义时的顺序传入:

python
def greet(first_name, last_name):
    return f"hello, {first_name} {last_name}"

greet("Alice", "Smith")   # 'hello, Alice Smith'

位置参数的顺序很重要,传反了结果就错:

python
greet("Smith", "Alice")   # 'hello, Smith Alice'

二、默认参数

给参数指定默认值,调用时可以不传:

python
def greet(name, greeting="hello"):
    return f"{greeting}, {name}"

greet("Alice")              # 'hello, Alice'
greet("Alice", "hi")        # 'hi, Alice'
greet("Alice", greeting="hey")   # 'hey, Alice'

带默认值的参数要放在参数列表末尾:

python
def greet(name, greeting="hello"):       # 正确
def greet(greeting="hello", name):       # SyntaxError

默认参数的陷阱:默认值在函数定义时求值,只执行一次。如果默认值是可变对象(如列表、字典),多次调用会共享同一个对象:

python
def append_item(item, items=[]):
    items.append(item)
    return items

append_item("a")    # ['a']
append_item("b")    # ['a', 'b'],不是 ['b']!

修复:用 None 作为默认值,在函数内部创建新对象:

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

这是 Python 最常见的默认参数陷阱。可变默认值(列表、字典、集合)一定要避开。

三、关键字参数

调用时显式指定参数名,顺序不重要:

python
def create_user(name, age, city):
    return {"name": name, "age": age, "city": city}

create_user(age=25, city="Beijing", name="Alice")

关键字参数在参数较多时很有价值——不用记顺序,代码自解释。

混合使用时,位置参数必须在关键字参数前面:

python
create_user("Alice", age=25, city="Beijing")   # 正确
create_user(name="Alice", 25, "Beijing")        # SyntaxError

四、可变参数 *args

不确定传入多少个位置参数时,用 *args

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

sum_all(1, 2, 3)      # 6
sum_all()             # 0

numbers 是一个元组,包含所有传入的位置参数。

args 是约定俗成的名字,可以改。* 才是真正起作用的语法。

已有的列表/元组可以解包传入:

python
values = [1, 2, 3, 4]
sum_all(*values)   # 等价于 sum_all(1, 2, 3, 4),* 把序列拆开

五、关键字可变参数 **kwargs

不确定传入多少个关键字参数时,用 **kwargs

python
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25)
# name: Alice
# age: 25

kwargs 是一个字典。已有的字典可以解包传入:

python
data = {"name": "Alice", "age": 25}
print_info(**data)   # 等价于 print_info(name="Alice", age=25)

六、参数顺序

定义函数时,参数必须按这个顺序排列:

python
def func(位置参数, 默认参数, *args, 仅限关键字参数, **kwargs):
    pass

完整示例:

python
def process(name, mode="fast", *extra, timeout=30, **options):
    print(f"name={name}, mode={mode}")
    print(f"extra={extra}")
    print(f"timeout={timeout}")
    print(f"options={options}")

process("task1", "slow", "arg1", "arg2", timeout=60, retry=3)
# name=task1, mode=slow
# extra=('arg1', 'arg2')
# timeout=60
# options={'retry': 3}

七、仅限关键字参数

参数在 *args 之后,或单独用 * 分隔,只能通过关键字传入:

python
def greet(name, *, greeting="hello"):
    return f"{greeting}, {name}"

greet("Alice")                  # 正确
greet("Alice", greeting="hi")   # 正确
greet("Alice", "hi")            # TypeError,greeting 必须用关键字

这个机制强制调用方显式写出参数名,避免位置传参的歧义。适合那些"可选但重要"的参数。

记忆锚点:默认参数在定义时求值,只执行一次,可变默认值用 None 占位;*args 收多余位置参数,**kwargs 收多余关键字参数;*序列 解包传入,**字典 解包传入;参数顺序:位置 → 默认 → *args → 仅限关键字 → **kwargs* 后的是仅限关键字参数。