关键字参数
关键字参数(Keyword Arguments)让函数调用更清晰、更灵活。调用方通过 name=value 的形式指定参数,不必记住参数的顺序。
基本用法
def greet(name, greeting, punctuation):
print "%s, %s%s" % (greeting, name, punctuation)
# 位置调用:必须按顺序
greet("Alice", "Hello", "!")
# 关键字调用:顺序任意
greet(punctuation="?", name="Bob", greeting="Hi")
# 混合调用:位置参数在前,关键字参数在后
greet("Charlie", punctuation="...", greeting="Hey")
混合调用时,位置参数按顺序匹配,关键字参数按名字匹配。但关键字参数不能出现在位置参数之前:
greet(name="Alice", "Hello") # SyntaxError: non-keyword arg after keyword arg
可读性的提升
关键字参数让代码自文档化:
# 不清楚 80 和 30 是什么
connect("example.com", 80, 30)
# 一目了然
connect("example.com", port=80, timeout=30)
在团队协作中,关键字参数能显著降低理解成本。尤其是参数类型相同(都是数字或字符串)时,位置调用极易出错:
def send_email(to, subject, body):
pass
# 容易搞错顺序
send_email("Hello", "boss@example.com", "Meeting at 3pm")
# 清晰且安全
send_email(to="boss@example.com", subject="Hello", body="Meeting at 3pm")
与默认参数配合
关键字参数和默认参数结合,可以只修改需要的参数:
def draw_circle(x, y, radius=10, color="black", fill=False):
print "Circle at (%d, %d), r=%d, color=%s, fill=%s" % (x, y, radius, color, fill)
# 只改颜色
draw_circle(100, 200, color="red")
# 只改半径和填充
draw_circle(100, 200, radius=20, fill=True)
注意:调用 draw_circle(100, 200, color="red") 时,radius 使用默认值 10,color 被指定为 "red"。
强制关键字参数(Python 3 特性)
Python 2 没有强制关键字参数的语法。Python 3 可以用 * 实现:
# Python 3
def func(a, b, *, c, d):
pass
func(1, 2, c=3, d=4) # 正确
func(1, 2, 3, 4) # 错误,c 和 d 必须用关键字
Python 2 中可以用 **kwargs 模拟,但没有同等优雅的语法。
关键字参数与字典解包
可以用字典解包来动态传递关键字参数:
def greet(name, greeting, punctuation):
print "%s, %s%s" % (greeting, name, punctuation)
params = {
"name": "Alice",
"greeting": "Hello",
"punctuation": "!"
}
greet(**params) # Hello, Alice!
**params 把字典的键值对作为关键字参数传入。这在配置驱动、框架开发中非常常见。
常见错误
重复赋值:
greet("Alice", name="Bob") # TypeError: greet() got multiple values for keyword argument 'name'
位置参数 "Alice" 已经赋给 name,后面的 name="Bob" 又试图赋值。
未知参数:
greet("Alice", unknown="value") # TypeError: greet() got an unexpected keyword argument 'unknown'
最佳实践
- 参数超过 3 个时,考虑用关键字调用
- 布尔参数必须用关键字:
func(enable=True)比func(True)清晰 - 文档中说明哪些参数推荐用关键字调用
- API 设计时,把不常用参数放在后面并设默认值