可变参数
有时函数需要接受任意数量的参数。Python 提供了 *args 和 **kwargs 两种机制,分别收集多余的位置参数和关键字参数。
*args:收集多余位置参数
def total(*args):
result = 0
for num in args:
result += num
return result
print total() # 0
print total(1) # 1
print total(1, 2, 3) # 6
print total(1, 2, 3, 4, 5) # 15
*args 把多余的位置参数收集成一个元组。在函数内部,args 是一个普通元组,可以遍历、索引、求长度。
def show_args(first, *args):
print "first:", first
print "rest:", args
print "count:", len(args)
show_args("a", "b", "c", "d")
# first: a
# rest: ('b', 'c', 'd')
# count: 3
**kwargs:收集多余关键字参数
def show_info(**kwargs):
for key, value in kwargs.iteritems():
print "%s = %s" % (key, value)
show_info(name="Alice", age=25, city="Beijing")
# name = Alice
# age = 25
# city = Beijing
**kwargs 把多余的关键字参数收集成一个字典。在函数内部,kwargs 是一个普通字典。
组合使用
def func(a, b, *args, **kwargs):
print "a:", a
print "b:", b
print "args:", args
print "kwargs:", kwargs
func(1, 2, 3, 4, 5, x=10, y=20)
# a: 1
# b: 2
# args: (3, 4, 5)
# kwargs: {'y': 20, 'x': 10}
参数顺序必须是:位置参数 → *args → 关键字参数 → **kwargs。
解包调用
调用函数时,可以用 * 和 ** 解包序列和字典:
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print add(*nums) # 6,等价于 add(1, 2, 3)
params = {"a": 1, "b": 2, "c": 3}
print add(**params) # 6,等价于 add(a=1, b=2, c=3)
组合使用:
def func(a, b, c, d, e):
return a + b + c + d + e
args = [1, 2]
kwargs = {"d": 4, "e": 5}
print func(*args, 3, **kwargs) # 15
# 等价于 func(1, 2, 3, d=4, e=5)
实际应用
装饰器:
def my_decorator(func):
def wrapper(*args, **kwargs):
print "Before call"
result = func(*args, **kwargs)
print "After call"
return result
return wrapper
@my_decorator
def greet(name):
print "Hello,", name
greet("Alice")
# Before call
# Hello, Alice
# After call
装饰器不知道被装饰函数的参数签名,用 *args, **kwargs 可以适配任何函数。
转发参数:
def log_and_call(func, *args, **kwargs):
print "Calling %s with %s, %s" % (func.__name__, args, kwargs)
return func(*args, **kwargs)
log_and_call(max, 1, 5, 3)
# Calling max with (1, 5, 3), {}
# 返回 5
命名约定
*args:多余位置参数(可以叫其他名字,但args是约定)**kwargs:多余关键字参数(可以叫其他名字,但kwargs是约定)
常见错误
*args 已经是元组,不要再用 *:
def bad(*args):
print *args # SyntaxError!print 是语句,不能这样用
def good(*args):
print args # 正确
print " ".join(str(a) for a in args)
**kwargs 的键必须是字符串:
def func(**kwargs):
pass
func(**{1: "a"}) # TypeError: func() keywords must be strings