Python 编程技术:函数的参数
在 Python 中,函数的参数传递非常灵活。Python 是一种动态类型语言,因此函数参数不需要声明类型,传入什么类型的值都可以。Python 的函数参数主要分为以下几种类型:
基础参数类型
位置参数(Positional Arguments)
这是最常见的参数类型。调用函数时,按照参数定义的顺序依次传入对应的值。
def greet(name, age):
print(f"{name} is {age} years old.")
greet("Alice", 25) # 正确
注意:如果传参顺序不对,可能导致逻辑错误。
关键字参数(Keyword Arguments)
在调用函数时,可以使用 参数名=值
的方式传参,这样可以不考虑参数的顺序。
def greet(name, age):
print(f"{name} is {age} years old.")
greet(age=30, name="Bob") # 正确,顺序无关
默认参数(Default Arguments)
定义函数时可以为参数指定默认值。如果调用时没有传该参数,则使用默认值。
def greet(name, age=18):
print(f"{name} is {age} years old.")
greet("Charlie") # 输出: Charlie is 18 years old.
greet("David", 22) # 输出: David is 22 years old.
注意
-
虽然函数的参数类型有很多种,但是一个参数传递给函数的方式有且只有两种:位置传递和关键字传递。在没有特殊限制(后面会讲到)的情况下,一个位置参数可以被当作关键字参数传递,一个关键字参数也能被当作位置参数传递:
def greet(name, age=18): print(f"{name} is {age} years old.") greet("Alice", 25) # 都按位置传递,输出: Alice is 25 years old. greet(name="Bob", age=30) # 都按关键字传递,输出: Bob is 30 years old.
但是,一个以关键字传递的参数必须出现在位置传递的参数之后:
def greet(name, age=18): print(f"{name} is {age} years old.") greet(name=8, "Jane") # SyntaxError: positional argument follows keyword argument
-
默认参数只在函数定义时求值一次,不要使用可变对象作为默认参数(如列表或字典),否则会导致意外行为。
错误示例:
def add_item(item, lst=[]): lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2] ← 意外行为!
推荐写法:
def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst
可变数量参数(Variable-length Arguments)
用于接收任意数量的位置参数或关键字参数。
*args
- 接收任意数量的位置参数(打包成元组)
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3)) # 输出: 6
print(sum_all(4, 5)) # 输出: 9
**kwargs
- 接收任意数量的关键字参数(打包成字典)
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Eve", age=28, city="Shanghai")
# 输出:
# name: Eve
# age: 28
# city: Shanghai
仅限关键字参数(Keyword-only Arguments)
从 Python 3 开始支持“强制关键字参数”,即某些参数必须通过关键字传参,不能按位置传参。
def greet(*, name, age):
print(f"{name} is {age} years old.")
greet(name="Frank", age=30) # 正确
greet("Frank", 30) # 报错 TypeError
也可以在 *args
后面添加关键字参数,使其成为仅限关键字参数:
def func(a, b, *args, c, d):
print(f"a={a}, b={b}, args={args}, c={c}, d={d}")
func(1, 2, 3, 4, c=5, d=6)
# 输出: a=1, b=2, args=(3, 4), c=5, d=6
仅限位置参数(Positional-only Arguments)
从 Python 3.8 开始,支持“仅限位置参数”,即某些参数只能通过位置传参,不能使用关键字传参。这种参数在函数定义中使用 /
分隔符来指定:位于 /
左侧的参数是仅限位置参数。
def greet(name, age, /):
print(f"{name} is {age} years old.")
greet("Helen", 26) # 正确
greet(name="Helen", age=26) # 报错 TypeError: greet() got some positional-only arguments passed as keyword arguments: 'name, age'
更复杂的示例:混合使用位置参数和关键字参数
可以在函数定义中同时使用 /
和 *
来明确哪些参数是仅限位置的,哪些是仅限关键字的:
def func(a, b, /, c, d, *, e, f):
print(f"a={a}, b={b}, c={c}, d={d}, e={e}, f={f}")
func(1, 2, 3, d=4, e=5, f=6) # 正确调用方式
# a 和 b 是仅限位置参数
# c 可以按位置或关键字传参
# d 可以按位置或关键字传参
# e 和 f 是仅限关键字参数
注意:
/
表示仅限位置参数的结束;*
表示仅限关键字参数的开始。
使用场景
-
当需要 API 的使用者严格按照顺序传递参数时;
-
提高接口清晰度,避免歧义(如参数名可能重复或含糊);
-
某些内置函数为了保持与 C 实现的一致性,也需要仅限位置参数。
参数解包(Argument Unpacking)
可以在调用函数时使用 *
或 **
来解包序列或字典。
使用 *
解包列表/元组
def add(a, b):
return a + b
nums = [3, 4]
print(add(*nums)) # 等效于 add(3, 4)
使用 **
解包字典
def greet(name, age):
print(f"{name} is {age} years old.")
info = {"name": "Grace", "age": 27}
greet(**info) # 等效于 greet(name="Grace", age=27)
总结
参数类型 | 关键字/符号 | 是否必须 | 特点说明 |
---|---|---|---|
位置参数 | 无 | 是 | 必须按顺序传入 |
关键字参数 | 参数名=值 | 否 | 可以打乱顺序传参 |
默认参数 | 参数=默认值 | 否 | 有默认值,可省略 |
可变位置参数 | *args | 否 | 接收多个位置参数,打包为元组 |
可变关键字参数 | **kwargs | 否 | 接收多个关键字参数,打包为字典 |
仅限关键字参数 | *后定义 | 是 | 必须用关键字传参 |
仅限位置参数 | /后定义 | 是 | 必须用位置传参 |