解包在英文里叫作 Unpacking,就是将容器里面的元素逐个取出来(防杠精:此处描述并不严谨,由于容器中的元素并无发生改变)放在其它地方,比如你老婆去菜市场买了一袋苹果回来分别发给家里的每一个成员,这个过程就是解包。Python 中的解包是自动完成的,例如:javascript
>>> a, b, c = [1,2,3] >>> a 1 >>> b 2 >>> c 3
若是列表中有3个元素,那么恰好能够分配给3个变量。除了列表对象能够解包以外,任何可迭代对象都支持解包,可迭代对象包括元组、字典、集合、字符串、生成器等实现了__next__方法的一切对象。java
元组解包python
>>> a,b,c = (1,2,3) >>> a 1 >>> b 2 >>> c 3
字符串解包函数
>>> a,b,c = "abc" >>> a 'a' >>> b 'b' >>> c 'c'
字典解包测试
>>> a,b,c = {"a":1, "b":2, "c":3} >>> a 'a' >>> b 'b' >>> c 'c'
字典解包后,只会把字典的 key 取出来,value 则丢掉了。ui
你可能见过多变量赋值操做,例如:spa
>>> a, b = 1, 2 >>> a 1 >>> b 2
本质上也是自动解包过程,等号右边实际上是一个元组对象 (1, 2),有时候咱们代码不当心多了一个逗号 ,,就变成了元组对象code
>>> a = 1, >>> a (1,) ---------- >>> a = 1 >>> a 1
因此写代码的时候须要特别注意。在 Python 中,交换两个变量很是方便,本质上也是自动解包过程。对象
>>> a, b = 1, 2 >>> a, b = b, a >>> a 2 >>> b 1
若是在解包过程当中,遇到左边变量个数小于右边可迭代对象中元素的个数时该怎么办? 比如大家家有3口人,你老婆却买了4个苹果,怎么分配呢?blog
在 Python2 中,若是等号左边变量的个数不等于右边可迭代对象中元素的个数,是不容许解包的。但在 Python3 能够这么作了。这个特性能够在 PEP 3132 中看到。
>>> a, b, *c = [1,2,3,4] >>> a 1 >>> b 2 >>> c [3, 4] >>>
这种语法就是在某个变量面前加一个星号,并且这个星号能够放在任意变量,每一个变量都分配一个元素后,剩下的元素都分配给这个带星号的变量
>>> a, *b, c = [1,2,3,4] >>> a 1 >>> b [2, 3] >>> c 4
这种语法有什么好处呢?它使得你的代码写起来更简洁,好比上面例子,在 Python2 中该怎么操做呢?思考3秒钟,再看答案。
>>> n = [1,2,3,4] # 使用切片操做 >>> a, b, c = n[0], n[1:-1], n[-1] >>> a 1 >>> b [2, 3] >>> c 4
以上是表达式解包的一些操做,接下来介绍函数调用时的解包操做。函数调用时,有时你可能会用到两个符号:星号和 双星号*。
>>> def func(a,b,c):
... print(a,b,c)
...
>>> func(1,2,3) 1 2 3
func 函数定义了三个位置参数 a,b,c,调用该函数必须传入三个参数,除此以外,你也能够传入包含有3个元素的可迭代对象,
>>> func(*[1,2,3]) 1 2 3 >>> func(*(1,2,3)) 1 2 3 >>> func(*"abc") a b c >>> func(*{"a":1,"b":2,"c":3}) a b c
函数被调用的时候,使用星号 * 解包一个可迭代对象做为函数的参数。字典对象,可使用两个星号,解包以后将做为关键字参数传递给函数
>>> func(**{"a":1,"b":2,"c":3}) 1 2 3
看到了吗?和上面例子的区别是多了一个星号,结果彻底不同,缘由是什么? 答案是** 符号做用的对象是字典对象,它会自动解包成关键字参数 key=value 的格式:
>>> func(a=1,b=2,c=3) 1 2 3
若是字典对象中的 key 不是 a,b,c,会出现什么状况?请读者自行测试。
总结一下,一个星号可做用于全部的可迭代对象,称为迭代器解包操做,做为位置参数传递给函数,两个星号只能做用于字典对象,称之为字典解包操做,做为关键字参数传递给函数。使用 和 * 的解包的好处是能节省代码量,使得代码看起来更优雅,否则你得这样写:
>>> d = {"a":1, "b":2, "c":3} >>> func(a = d['a'], b=d['b'], c=d['c']) 1 2 3 >>>
到这里,解包还没介绍完,由于 Python3.5,也就是 PEP 448 对解包操做作了进一步扩展, 在 3.5 以前的版本,函数调用时,一个函数中解包操做只容许一个 和 一个*。从 3.5 开始,在函数调用中,能够有任意多个解包操做,例如:
# Python 3.4 中 print 函数 不容许多个 * 操做 >>> print(*[1,2,3], *[3,4]) File "<stdin>", line 1 print(*[1,2,3], *[3,4]) ^ SyntaxError: invalid syntax >>>
再来看看 python3.5以上版本
# 可使用任意多个解包操做
>>> print(*[1], *[2], 3) 1 2 3
从 3.5 开始能够接受多个解包,于此同时,解包操做除了用在函数调用,还能够做用在表达式中。
>>> *range(4), 4 (0, 1, 2, 3, 4) >>> [*range(4), 4] [0, 1, 2, 3, 4] >>> {*range(4), 4} {0, 1, 2, 3, 4} >>> {'x': 1, **{'y': 2}} {'x': 1, 'y': 2}
新的语法使得咱们的代码更加优雅了,例如拼接两个列表能够这样:
>>> list1 = [1,2,3] >>> list2 = range(3,6) >>> [*list1, *list2] [1, 2, 3, 3, 4, 5] >>>
可不能够直接用 + 操做呢?不行,由于 list 类型没法与 range 对象相加,你必须先将 list2 强制转换为 list 对象才能作 +操做,这个留给读者自行验证。
再来看一个例子:如何优雅的合并两个字典
>>> a = {"a":1, "b":2} >>> b = {"c":3, "d":4} >>> {**a, **b} {'a': 1, 'b': 2, 'c': 3, 'd': 4}
在3.5以前的版本,你不得不写更多的代码:
>>> import copy >>> >>> c = copy.deepcopy(a) >>> c.update(b) >>> c {'a': 1, 'b': 2, 'c': 3, 'd': 4}
到此,关于 Python 解包给你介绍完了,若是本文对你有收获,请点赞、转发支持。
最后给你总结一下:
自动解包支持一切可迭代对象