函数的参数
Python 函数参数灵活:除必选参数外,还有默认参数、可变参数、关键字参数、命名关键字参数,可组合使用。
1. 位置参数
- 调用时按位置顺序传入,依次赋给参数。
- 示例:
power(x, n)中x、n都是位置参数;power(5, 2)→ x=5, n=2。
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
power(5, 2) # 25
power(5, 3) # 125
2. 默认参数
- 定义时给参数默认值,调用时可省略,简化调用。
- 顺序:必选参数在前,默认参数在后;变化大的在前,变化小的在后(变化小的适合做默认值)。
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
power(5) # 25,等价于 power(5, 2)
power(5, 3) # 125
- 多默认参数:可按顺序提供,也可不按顺序时写参数名,如
enroll('Adam', 'M', city='Tianjin')。
默认参数必须用不可变对象
- 坑:默认参数在定义时就被计算出来;若默认值是可变对象(如
L=[]),多次调用会共用同一个对象,导致“记住”上次修改。
# 错误示例
def add_end(L=[]):
L.append('END')
return L
add_end() # ['END']
add_end() # ['END', 'END'] ← 错误!
- 正确:默认值用不可变对象,可变情况在函数内新建,如用
None:
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
add_end() # ['END']
add_end() # ['END'] ← 正确
记忆:默认参数必须指向不可变对象(str、None、数字等)。
3. 可变参数
- 传入的个数可变(0 个到任意个);在参数前加
*,函数内收到的是一个 tuple。
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
calc(1, 2, 3) # 14
calc(1, 3, 5, 7) # 84
calc() # 0
- 已有 list/tuple 时:在变量前加
*,把元素“展开”为可变参数传入:
nums = [1, 2, 3]
calc(*nums) # 14,等价于 calc(1, 2, 3)
记忆:*args → 接收 tuple;传入时 func(1,2,3) 或 func(*list)。
4. 关键字参数
- 传入 0 个或任意个“参数名=值”;在参数前加
**,函数内收到的是一个 dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
person('Michael', 30) # other: {}
person('Bob', 35, city='Beijing') # other: {'city': 'Beijing'}
person('Adam', 45, gender='M', job='Engineer') # other: {'gender': 'M', 'job': 'Engineer'}
- 已有 dict 时:在变量前加
**,把 key-value 作为关键字参数传入;函数内kw是拷贝,改kw不影响外部 dict。
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra) # other: {'city': 'Beijing', 'job': 'Engineer'}
记忆:**kw → 接收 dict;传入时 func(a=1, b=2) 或 func(**dict)。
5. 命名关键字参数
- 限制调用者只能传入指定名字的关键字参数;需要特殊分隔符
*,*后面的参数即命名关键字参数。 - 若已有可变参数
*args,则*args后面的参数就是命名关键字参数,不需要再写*。
# 无可变参数:必须写 *
def person(name, age, *, city, job):
print(name, age, city, job)
# 有可变参数:*args 后的即为命名关键字
def person(name, age, *args, city, job):
print(name, age, args, city, job)
person('Jack', 24, city='Beijing', job='Engineer') # 必须写参数名
# person('Jack', 24, 'Beijing', 'Engineer') # 报错:missing keyword-only arguments
- 命名关键字可有默认值,有默认值则可选传:
def person(name, age, *, city='Beijing', job):,调用时可只传job='Engineer'。
记忆:命名关键字必须传参数名;无可变参数时定义里不能省 *,否则会被当成位置参数。
6. 参数组合与顺序
- 定义顺序(固定):必选参数 → 默认参数 → 可变参数 → 命名关键字参数 → 关键字参数。
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
- 调用:可用 tuple + dict 解包调用任意函数:
f1(*args, **kw)、f2(*args, **kw);解释器按位置和参数名自动对应。
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw) # a=1 b=2 c=3 args=(4,) kw={'d':99,'x':'#'}
提示:不要同时用太多组合,否则接口难理解。
小结
| 参数类型 | 语法 | 函数内类型 | 传入方式 |
|---|---|---|---|
| 位置参数 | a, b | — | 按位置 |
| 默认参数 | a=0 | — | 可省略;默认值必须不可变对象 |
| 可变参数 | *args | tuple | func(1,2,3) 或 func(*list) |
| 命名关键字 | *, city, job 或 *args, city, job | — | 必须写参数名 city=..., job=... |
| 关键字参数 | **kw | dict | func(a=1) 或 func(**dict) |
- 定义顺序:必选 → 默认 → 可变 → 命名关键字 → 关键字。
- 默认参数:一定要用不可变对象;可变对象用
None在函数内再赋值。 - 命名关键字:无可变参数时不能省
*;调用时必须传参数名。
练习:把 mul(x, y) 改成可接收一个或多个数并计算乘积(可变参数)。