Appearance
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() # 0numbers 是一个元组,包含所有传入的位置参数。
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: 25kwargs 是一个字典。已有的字典可以解包传入:
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;* 后的是仅限关键字参数。