解包在英文裏叫作 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 解包給你介紹完了,若是本文對你有收穫,請點贊、轉發支持。
最後給你總結一下:
自動解包支持一切可迭代對象