Python中*args和**kwargs的使用
技术背景
在Python编程中,有时我们需要定义一个能接受任意数量参数的函数。*args
和 **kwargs
就是Python提供的两个强大特性,用于处理这种情况。*args
用于接收任意数量的位置参数,它会将这些参数封装成一个元组;**kwargs
用于接收任意数量的关键字参数,它会将这些参数封装成一个字典。
实现步骤
1. 使用 *args
当不确定函数会接收多少个位置参数时,可以使用 *args
。示例代码如下:
1 2 3 4 5
| def print_everything(*args): for count, thing in enumerate(args): print('{0}. {1}'.format(count, thing))
print_everything('apple', 'banana', 'cabbage')
|
在上述代码中,*args
接收了三个位置参数,并将它们封装成一个元组。然后通过 enumerate
函数遍历这个元组并打印每个元素。
2. 使用 **kwargs
当需要处理未预先定义的关键字参数时,可以使用 **kwargs
。示例代码如下:
1 2 3 4 5
| def table_things(**kwargs): for name, value in kwargs.items(): print('{0} = {1}'.format(name, value))
table_things(apple='fruit', cabbage='vegetable')
|
在这个例子中,**kwargs
接收了两个关键字参数,并将它们封装成一个字典。然后通过 items
方法遍历这个字典并打印每个键值对。
3. 结合使用 *args 和 **kwargs
可以在同一个函数定义中同时使用 *args
和 **kwargs
,但 *args
必须在 **kwargs
之前。示例代码如下:
1 2 3 4 5 6 7 8
| def func(required_arg, *args, **kwargs): print(required_arg) if args: print(args) if kwargs: print(kwargs)
func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
|
在这个函数中,required_arg
是一个必需的位置参数,*args
接收额外的位置参数,**kwargs
接收额外的关键字参数。
4. 在函数调用中使用 * 和 **
*
和 **
语法也可以在函数调用时使用,用于解包列表或字典。示例代码如下:
1 2 3 4 5
| def print_three_things(a, b, c): print('a = {0}, b = {1}, c = {2}'.format(a, b, c))
mylist = ['aardvark', 'baboon', 'cat'] print_three_things(*mylist)
|
在这个例子中,*mylist
将列表 mylist
解包成三个独立的参数,并传递给 print_three_things
函数。
核心代码
以下是几个使用 *args
和 **kwargs
的完整示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| def sumFunction(*args): result = 0 for x in args: result += x return result
print(sumFunction(3, 4, 6, 3, 6, 8, 9))
def someFunction(**kwargs): if 'text' in kwargs: print(kwargs['text'])
someFunction(text="foo")
import functools
def mydecorator(f): @functools.wraps(f) def wrapper(*args, **kwargs): print("Calling f", args, kwargs) v = f(*args, **kwargs) print("f returned", v) return v return wrapper
@mydecorator def example_function(a, b): return a + b
print(example_function(2, 3))
|
最佳实践
1. 子类化
在子类化时,使用 *args
和 **kwargs
可以方便地扩展父类的行为,而无需了解父类的具体参数。示例代码如下:
1 2 3 4 5 6 7 8 9 10
| class Foo(object): def __init__(self, value1, value2): print(value1, value2)
class MyFoo(Foo): def __init__(self, *args, **kwargs): print('myfoo') super(MyFoo, self).__init__(*args, **kwargs)
my_foo = MyFoo(1, 2)
|
2. 包装函数
在编写包装函数(如装饰器)时,使用 *args
和 **kwargs
可以接受任意参数并传递给被包装的函数。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import functools
def mydecorator(f): @functools.wraps(f) def wrapper(*args, **kwargs): print("Calling f", args, kwargs) v = f(*args, **kwargs) print("f returned", v) return v return wrapper
@mydecorator def example_function(a, b): return a + b
print(example_function(2, 3))
|
常见问题
1. 能否在函数调用的中间扩展列表作为位置参数?
在Python 2中,无法在函数调用的中间扩展列表作为位置参数。但在Python 3中,这种操作是可行的。
2. *args
和 **kwargs
必须使用这两个名称吗?
不是的,*
和 **
是语法,args
和 kwargs
只是约定俗成的名称,你可以使用其他名称,但为了代码的可读性,建议使用这两个名称。
3. 在Python 2中,能否使用 *args
扩展与 print
语句一起使用?
在Python 2中,print
是语句而不是函数,因此不能使用 *args
扩展与 print
语句一起使用。但可以通过 from __future__ import print_function
来将 print
作为函数使用,或者手动遍历 args
并打印每个元素。在Python 3中,print
是函数,可以直接使用 *args
扩展。