GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||
GeezerVison is showing notes.kamacoder.com — Python位置参数、关键字参数、args和*kwargs怎么用?参数传递与解包 # 位置参数、关键字参数、 |
| 位置 | 参数类型 | 说明 |
|---|---|---|
/之前 | 仅限位置参数 | 只能按位置传递 |
/之后、*args之前 | 位置或关键字参数 | 可以按位置或关键字传递 |
*args | 可变位置参数 | 收集多余位置参数 |
*args之后、**kwargs之前 | 仅限关键字参数 | 只能按关键字传递 |
**kwargs | 可变关键字参数 | 收集多余关键字参数 |
示例:
def example(a, b, /, c, d, *args, e, f=10, **kwargs):
print(f"a={a}, b={b}, c={c}, d={d}")
print(f"args={args}")
print(f"e={e}, f={f}")
print(f"kwargs={kwargs}")
example(1, 2, 3, 4, 5, 6, e=7, f=8, g=9, h=10)
# a=1, b=2, c=3, d=4
# args=(5, 6)
# e=7, f=8
# kwargs={'g': 9, 'h': 10}
a和b必须按位置传递,c和d可以按位置或关键字传递,5和6被*args收集,e和f必须用关键字传递,g和h被**kwargs收集。

单独的*之后的参数只能用关键字传递:
def create_user(name, *, email, age):
return {"name": name, "email": email, "age": age}
user = create_user("Alice", email="[email protected]", age=25)
# 正确
user = create_user("Alice", "[email protected]", 25)
# TypeError: create_user() takes 1 positional argument but 3 were given
这种设计强制调用方明确参数含义,提高可读性。
单独的/之前的参数只能按位置传递:
def divide(a, b, /):
return a / b
print(divide(10, 2)) # 5.0
print(divide(a=10, b=2))
# TypeError: divide() got some positional-only arguments passed as keyword arguments: 'a, b'
仅限位置参数是Python 3.8引入的语法,用于保护参数名不被暴露,允许后续修改参数名而不破坏调用方代码。
调用时可以用*解包序列,用**解包字典:
def add(a, b, c):
return a + b + c
values = [1, 2, 3]
print(add(*values)) # 6,等价于add(1, 2, 3)
params = {"a": 1, "b": 2, "c": 3}
print(add(**params)) # 6,等价于add(a=1, b=2, c=3)
解包时,序列长度必须与位置参数数量匹配,字典的键必须与参数名匹配。
Q1:*args和**kwargs的名字可以改吗?
可以。*和**是语法,args和kwargs只是约定俗成的名字。可以写成*numbers或**options,但不建议改,因为会降低代码可读性。
Q2:为什么*args必须在**kwargs之前?
因为调用时位置参数必须在关键字参数之前。*args收集位置参数,**kwargs收集关键字参数,定义顺序必须匹配调用顺序。
Q3:如何限制*args或**kwargs的内容?
函数内检查:
def create_user(*args, **kwargs):
if len(args) > 0:
raise TypeError("create_user() takes 0 positional arguments")
allowed_keys = {"name", "email", "age"}
for key in kwargs:
if key not in allowed_keys:
raise TypeError(f"Unexpected keyword argument: {key}")
或者改用明确参数,不用**kwargs。
Q4:调用时能同时用*和**解包吗?
可以:
args = [1, 2]
kwargs = {"c": 3}
print(add(*args, **kwargs)) # 6
但注意不要重复传递同一个参数,否则会抛出TypeError。
Q5:什么时候用*args和**kwargs?
print、max)。不要滥用。能用明确参数就用明确参数,提高可读性和IDE提示能力。
验证登录状态...