理解和使用python中的拆包會讓我們的代碼變得流暢,不僅對自己的手關節有好處,也使看官覺得很賞心悅目,既然拆包這麼香那就抓緊用起來吧。
1、直接交換變量的本質
在C,C++和Java語言中如果想交換兩個變量的值就必須用到第三個臨時變量,但是在python中我們竟然可以做到不用經過第三方的手直接進行交換了,即省去了第三個變量又盡顯優雅,那麼他是如何實現的呢。
a = 1
b = 2
a, b = b, a
我們先說python中一個重要的數據結構,那就是元組
,在元組( )
可以省略,那麼上面的a, b = b, a
等式右邊的b, a
就自行構成了一個元組。
所以左邊就變成了對元組的拆包過程。直接交換變量的實質就是一個打包和拆包的過程。
2、常見的拆包操作
1、元組的拆包
tup = (1, 2, 3)
# 方式一
a, b, c = tup # 要求元組內的個數與接收的參數個數相同
print(a, b, c)
結果如下:
1 2 3
# 方式二
print(*tup) # 使用*進行拆包,結果同上
add(*tup)
如下方式是錯誤的
a, b, c = *tup
這兩種方式分別在什麼情況下使用呢?
- 方式一一般在要獲取元組的值時使用
- 方式二一般在函數調用時使用,見下面的函數中的裝包與拆包
下面介紹一點稍微複雜一點的拆包
tup = (1, 2, 3, 4, 5, 6)
比如說這個又6個數據的元組,我們感興趣的只有開頭和結尾的數據,不想要中間的數據,那需要像上面那樣弄6個參數來接受嗎?
a, *_, b = tup # 中間的數據被打包到了 _ 中,我們只獲取到了開頭和結尾的數據
從上面這個例子中我們可以看到,*
這個符號既可以用來拆包也可以用來打包。可以把任意多的數據打包起來。拆包過程中如果使用了
* 號,我們只能提取開頭或者結尾的感興趣數據。
還有下面這種,多層包含的拆包。(也可以包含列表和字典的數據結構)
tup = (1, 2, (3, 4, 5), 6)
拆包
a, b, c, d = tup
結果如下:
1 2 (3, 4, 5) 6
c就是中間哪個元組了。如果想進一步拆包,重複上述步驟即可。
我們看到,多餘的3, 4, 5這三個參數被打包到了*args
這個參數中去了。
2、列表的拆包與元組一樣
3、字典的拆包
其實用法與元組和列表一樣,只不過字典拆包得到值是key
而已。
dick = {"張三":18, "李四":22, "王五":24}
a, b, c = dick
張三 李四 王五
4、函數參數的裝包與拆包
我們會經常看到如下形式定義的函數
def func(a, b, *args):
print(a, b)
print(type(args))
print(args)
如果我們這樣func(1, 2, 3, 4, 5, 6)調用函數,結果如下:
1 2
<class ‘tuple’>
(3, 4, 5, 6)
從結果出發我們可以得出如下結論:
- *args會把多餘參數打包
- 打包之後的類型爲元組
我們還可以這樣傳參數,
lis = (1, 2, 3, 4, 5, 6)
func(*lis) # 迴應上面方式二的使用情況
3、常見的應用場景
上面可以說是拆包的初相識,下面我們在來看看它的應用場景還有那些。
- 元組和列表的拆包打印
stars = ("黎明", "華仔", "郭富城", "張學友")
print("四大天王:%s, %s, %s, %s" % stars)
如果你寫成下面這樣的,會使什麼感受。太不pythonic
了吧。
stars = ("黎明", "華仔", "郭富城", "張學友")
print("四大天王:%s, %s, %s, %s" % (stars[0], stars[1], stars[2], stars[3]))
再來看看列表的打印。你們可能感覺列表和元組的結果一樣,但事實往往和我們想的它就不一樣。
stars = ["黎明", "華仔", "郭富城", "張學友"]
print("四大天王:%s, %s, %s, %s" % stars)
報錯,我只想說一句fucker,具體的原因我也沒查到。猜測是%後面不接受這種長度或者數據可變的數據類型作爲參數,當然只是猜測。
怎麼解這個BUG呢,
stars = ["黎明", "華仔", "郭富城", "張學友"]
print("四大天王:%s, %s, %s, %s" % (*stars,))
爲什麼會這樣呢,我不能只告訴你結果就完事了,那樣沒有意義,雖然我們不能把它的內褲拔下來一看究竟,那也得嘗試拔他最外面的一層皮。
(*stars,)
到底做了什麼。一定注意括號內的,
絕對不能丟。(*stars,)
到底是何方神聖呢,看下面結果,這個操作直接把列表變成了一個元組,不是又學到了,列表轉換成元組的又一種方法
。
還可以這麼做,不過道理也是一樣的:
print("四大天王:%s, %s, %s, %s" % tuple(stars))
即元組與列表的打印拆包中總結,只能默認拆包元組,如果是列表就先轉換成元組在拆包。