关键字: Python *args
**kwargs
0. 前言
上周和室友讨论他在科大讯飞面试的问题时,谈到了Python装饰器的含义和用途。于是乎今天重新复习了一下关于Python装饰器的内容。但在阅读Python装饰器的代码中,函数经常会出现*args
和**kwargs
等参数,虽然之前了解这两个参数表示可以输入数量不定的变量的含义,但并没有深入理解其含义和用法。写下此文作为理解*args
和**kwargs
的学习笔记。
1. ‘*表达式’
在讨论*args
和**kwargs
之前,我们需要先介绍一下Python中的‘*表达式’。
先看以下代码:
说明: >>>
表示是Python运行终端,本文所用的Python版本是3.5.2。
1 | 'snowball', 'USTC', '183xxxx1966', '188xxxx7604') user_info = ( |
观察上述代码,我们可以看到,当我们用name、school、phone_number三个变量去对含有4个元素的user_info元组进行解包时,就会出现too many values to unpack
的错误。但是元组中的第3个和第4个元素都是手机号码,我们又不想分别用两个变量对这两个号码进行保存,这时我们就可以通过‘*表达式’来实现我们的功能。*phone_number
表示的是一个列表,它将存储元组中剩下的所有元素。即使元组中剩下元素的个数为0,代码也不会报错,因为此时‘*表达式’所对应的是一个空列表。
同时,‘*表达式’也可以位于解包代码的第一个位置,举例说明:
1 | 0,1,2,3,4,5,6,7,8,9] *head, end = [ |
上述代码中,*head
表示的是包含原列表中前9个元素的列表,变量end
对应列表中的最后一个元素。在对列表的元素解包的过程中,*head
一直匹配到下一个解包元素的所对应的原列表的位置的前一个位置。进一步深入的理解,‘*表达式’的实现机制可和切片的实现机制进行类比。‘*表达式’相当于实现了对原始可迭代对象的切片操作(上述代码中的可迭代对象为列表),只不过‘*表达式’切片的长度是不定的,它的长度是由其它解包元素的个数来确定的。在上述代码中,*head
之后只有一个解包变量end
,所以*head
的长度即为原始列表的长度减1,可将其类比成取原始列表前9个元素的切片操作。
2. *args
和**kwargs
理解了‘*表达式’的含义和用法,再对Python中的*args
和**kwargs
这两个魔法变量进行理解,就不会显得那么突兀。首先我们必须了解的是,*args
和**kwargs
的写法只是约定俗称的,我们完全可以按照自己的喜好来给参数变量命名,例如*var
和**vars
。换句话说,变量中*
号是不可省略的,但*
之后的变量名可以自定义。
*args
和**kwargs
都主要用于函数定义,表示的是可将不定数量的参数传递给一个函数。这里不定数量的含义是指,我们预先并不清楚,函数的使用者究竟会传递多少个参数给函数。这时,使用*args
和**kwargs
将会帮助我们处理这种情况。
2.1 *args
的用法
*args
用来向函数传递一个非键值对的可变长度的参数列表。
1 | def test_var_args(f_arg, *argv): |
运行结果:
1 | first normal arg: snowball |
通过上述代码,我们可以对*args
的用法有了较为深刻的理解。
2.2 **kwargs
的用法
首先我们要知道的是,**kwargs
中的kw
的含义是key-word pairs,也就是键值对。所以**kwargs
的用法是,向函数传递一个不定长度的键值对。如果我们想要我们的函数能够处理带名字的参数,我们应该使用**kwargs
。
举个例子:
1 | def welcome(**kwargs): |
所以,当函数的形参是**kwargs
时,传入函数的实参必须是键值对。
2.3 使用*args
和**kwargs
调用函数
我们写一个小函数,代码如下:
1 | def test_args_kwargs(arg1, arg2, arg3): |
然后我们分别使用*args
和**kwargs
来将参数传递给上述函数,代码如下:
1 | "snowball", [1,2,3], 5) args = ( |
使用标准参数和*args
、**kwargs
的顺序如下:
1 | some_func(fargs, *args, **kwargs) |
举个例子:
1 | def test_formal_args_kwargs(fargs, *args, **kwargs): |
3. *args
和**kwargs
的使用场景
在Python Cookbook第三版的第9章的元编程中,涉及到了Python装饰器的相关代码,*args
和**kwargs
在装饰器中经常会出现,举例说明:
1 | import time |
上述中的代码是一个用于计算函数执行时间的装饰器。在装饰器内部的代码里,我们使用语句result = func(*args, **kwargs)
来表示传入被装饰函数的参数的所有可能的表达形式。这种写法在Python装饰器函数中极其常见。
代码的运行结果为:
1 | countdown 0.001141786553173828 |
参考文献:
- Python Cookbook 第三版
- http://book.pythontips.com/en/latest/args_and_kwargs.html