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:不定长位置参数
形参写成 *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 之后,因此只能用关键字传入:
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只是约定名,换名字不影响机制,但团队里统一用这两个名字更省事。