Python中的星号,`**`和`*`运算符
在Python中,我们经常可以见到**
和*
运算符,比如*args
和 **kwargs
,还有n**3
、*nums
等等。这里总结一下,在Python中 **
和*
的用法。
数学运算符
它们作为数学运算符是非常简单的:
*
用于乘法**
用于乘方
1 | 2 * 6 |
函数参数
*args
和 **kwargs
主要用于函数定义,是一种允许任意数量(即预先并不知道函数使用者会传递多少个参数给)的函数参数的习惯用法,可以参见Python的官方文档。
首先并不是必须写成*args
和**kwargs
。 只有变量前面的 *
(星号)才是必须的,也可以写成*var
和**vars
。 而写成*args
和**kwargs
只是一个通俗的命名约定。
*args
*args
是可变参数。*args
可以表示任意多个参数,它本质是一个 tuple。
1 | In [1]: def foo(*args): |
** **kwargs
**
**kwargs
是关键字参数,它本质上是一个 dict。
1 | In [5]: def bar(**kwargs): |
*args
和 **kwargs
都可以与普通参数混合,以允许向函数传递一组固定参数和一些可变的参数:
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
因此,如果同时使用 *args
和 **kwargs
时,*args
参数必须要在 **kwargs
之前。
1 | def foo(kind, *args, **kwargs): |
解包参数列表
在Python中,调用函数时,利用*
语句可以将参数列表解包,如下所示,foo
有两个参数,我们可以传入一个参数列表l
,然后利用*
运算符,解包参数列表:
1 | In [9]: def foo(bar, lee): |
序列解包
在Python3.0之后,Python提供了一种非常方便的办法解压可迭代对象赋值给多个变量 (Extended Iterable Unpacking)。
另外一种情况,假设你现在有一些用户的记录列表,每条记录包含一个名字、邮件,接着就是不确定数量的电话号码。 你可以像下面这样分解这些记录:
1 | 'Dave', 'dave@example.com', '773-555-1212', '847-555-1212') record = ( |
值得注意的是上面解压出的 phone_numbers
变量永远都是列表类型,不管解压的电话号码数量是多少(包括 0 个)。 所以,任何使用到 phone_numbers
变量的代码就不需要做多余的类型检查去确认它是否是列表类型了。
星号表达式也能用在列表的开始部分。比如,你有一个公司前 8 个月销售数据的序列, 但是你想看下最近一个月数据和前面 7 个月的平均值的对比。你可以这样做:
1 | *trailing_qtrs, current_qtr = sales_record |
下面是在 Python 解释器中执行的结果:
1 | 10, 8, 7, 1, 9, 5, 10, 3] *trailing, current = [ |
Keyword-Only Arguments
在Python3中,也加入了一个新的语法(参见 PEP 3102)
1 | def func(arg1, arg2, arg3, *, kwarg1, kwarg2): |
这个函数只接受3个位置参数,*
之后的所有内容只能作为关键字参数传递(只能由关键字提供的参数,并且永远不会被位置参数自动填充)。
Reference
-
函数的参数 —— 廖雪峰的官方网站-Python教程
-
What does ** (double star/asterisk) and * (star/asterisk) do for parameters? —— Stackoverflow
-
1.2 解压可迭代对象赋值给多个变量 —— Python Cookbook