Python的*和**运算符是什么意思?有什么区别?

看到这么一段Flask代码:

1
2
3
4
5
6
view_data = dict(
rows = posts[start:end],
page = page,
has_next_page = has_next_page,
)
return render_template('posts.html', **view_data)

代码中最后一行时,发现里边有**这样两个星号连在一起用的语法,不解其意。查阅资料后,才发现星号运算符还是真是神通广大。具体来说,有4种不同用途。

1. 算数运算符

* 表示乘法运算, **表示乘方运算。

1
2
3
4
>>> 3 * 2
6
>>> 3 ** 2
9

2. 序列解包

序列解包是Python的一种语法糖,可以用来简化代码。
普通的序列解包,要求赋值运算符=左侧的变量个数和右侧的变量值个数相等。示例如下:

1
2
3
4
5
>>> lat, lon = 108, 33
>>> lat
108
>>> lon
33

=左边的变量个数和右侧的变量值个数不相等,则解包失败报错:

1
2
3
4
5
>>> a, b = 1, 2, 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>>
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> a, b, c = 1, 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)
>>>

这时,就可以使用 `*`星号运算符来处理了。`*`运算符将右侧多余的变量值**按顺序合并**成一个序列赋值给`*`标记的变量,用法示例如下:
​```python
>>> a, *b = 1, 2, 3
>>> a
1
>>> b
[2, 3]
1
2
3
4
5
>>> *a, b = 1, 2, 3
>>> a
[1, 2]
>>> b
3
1
2
3
4
5
>>> a, *b = 1, 2
>>> a
1
>>> b
[2]
1
2
3
4
5
>>> a, *b = 1
>>> a
1
>>> b
[]

3. 函数形参

***都可以用作函数的形参,用来将不定数量的参数传递给一个函数。一个星号用来传递元组tuple,两个星号用来传递字典dict,通常用*args*kwargs来分别表示。
示例如下:

1
2
3
4
5
6
>>> def func(a, *args):
... print(a, args)
...
>>> func(1, 2, 3)
1 (2, 3)
>>>
1
2
3
4
5
>>> def func(a, **kwargs):
... print(a, kwargs)
...
>>> func(1, lat=108, lon=33)
1 {'lat': 108, 'lon': 33}
1
2
3
4
5
>>> def func(*args, **kwargs):
... print(args, kwargs)
...
>>> func(1, 2, 3, name='ocre', sex='male')
(1, 2, 3) {'name': 'ocre', 'sex': 'male'}

4. 函数实参

为避免实参过长,可以用***对多个参数进行打包,示例如下:

1
2
3
4
5
6
7
8
>>> def func(a, **kwargs):
... print(a, kwargs)
...
>>> func(1, name='ocre', sex='male')
1 {'name': 'ocre', 'sex': 'male'}
>>> data = {'name':'ocre', 'sex':'male'}
>>> func(1, **data)
1 {'name': 'ocre', 'sex': 'male'}

本文开头我碰到的情况,就属于最后这种用法。