1. 程式人生 > >Python元組拆包撿到8倍鏡快準狠

Python元組拆包撿到8倍鏡快準狠

# 元組拆包 元組是不可變列表,列表是通過索引取值的,元組也是: ```python tuple_test = (1, 2, 3) a = tuple_test[0] b = tuple_test[1] c = tuple_test[2] ``` 但Python是出了名的一行程式碼解決問題,元組拆包就是精髓技術之一: ```python a, b, c = tuple_test ``` ```python print("%s %s %s" % tuple_test) ``` 把元組一一對應拆出來,就叫做元組拆包。拆包有個要求,元組中的元素數量必須跟接受這些元素的空擋數一致,否則會報錯: ```python tuple_test = (1, 2, 3) a, b = tuple_test # ValueError: too many values to unpack (expected 2) ``` **`_`佔位符** 使用`_`佔位符可以解決這個問題: ```python tuple_test = (1, 2, 3) a, b, _ = tuple_test ``` 這樣就只獲取到部分資料了,這在取函式返回值時特別有用,比如: ```python import os _, filename = os.path.split("/home/dongfanger/.ssh/idrsa.pub") print(filename) # "idrsa.pub" ``` **`*`字首** 當返回值特別多時,`_`佔位符寫起來麻煩,可以用`*`來處理剩下的元素: ```python >>> a, b, *rest = range(5) >>> a, b, *rest (0, 1, [2, 3, 4]) ``` 注意`rest`是個列表,如果沒有足夠元素,會返回空列表: ```python >>> a, b, *rest = range(2) >>> a, b, *rest (0, 1, []) ``` `*`字首變數能放在任意位置,比如,放在中間: ```python >>> a, *body, c, d = range(5) >>> a, body, c, d (0, [1, 2], 3, 4) ``` 放在前面: ```python >>> *head, b, c, d = range(5) >>> head, b, c, d ([0, 1], 2, 3, 4) ``` 實在是妙啊。 `*`還有一個作用,把元組拆開作為函式引數: ```python >>> divmod(20, 8) (2, 4) >>> t = (20, 8) >>> divmod(*t) (2, 4) ``` > 經典寫法`*args`就是這個道理。 # 巢狀元組拆包 巢狀元組是指元組中有元組,比如`(1, 2, 3, (4, 5))`,對於巢狀元組,你可能會想要拆兩遍: ```python tuple_nest_test = (1, 2, 3, (4, 5)) a, b, c, d = tuple_nest_test x, y = d print(a, b, c, x, y) ``` 實際上能一步到位: ```python tuple_nest_test = (1, 2, 3, (4, 5)) a, b, c, (x, y) = tuple_nest_test print(a, b, c, x, y) ``` # 交換兩個變數的值 元組拆包提供了語法糖,對於交換兩個變數的值的常規寫法: ```python temp = a a = b b = temp ``` 可以切換為優雅寫法: ```python b, a = a, b ``` # 具名元組 元組很像資料庫表記錄,除了沒有表名和欄位名,`collections.namedtuple`具名元組補償了這個缺憾,它是一個工廠函式,可以用來構建一個帶欄位名的元組和一個有名字的類,比如: ```python import collections # 定義 Card = collections.namedtuple("Card", ["rank", "suit"]) # 初始化 card_test = Card("J", "hearts") # 使用 print(card_test.rank) # J print(card_test[1]) # hearts ``` > Card是表名,有兩個表字段rank和suit。 定義具名元組需要2個引數,第1個引數是類名,第2個引數是欄位名,既可以是可迭代物件(如列表和元組),也可以是空格間隔的字串: ```python Card = collections.namedtuple("Card", ("rank", "suit")) Card = collections.namedtuple("Card", "rank suit") ``` 初始化時以一串引數形式傳入建構函式: ```python card_test = Card("J", "hearts") ``` 既可以通過`.`運算子,也可以用索引來取值: ```python print(card_test.rank) print(card_test[1]) ``` 這個帶名字的元組,對除錯程式有很大幫助。 # 列表與元組 元組是不可變列表,它們就像雙胞胎,長相類似,內在性格卻有不同: ![](https://img2020.cnblogs.com/blog/1629545/202102/1629545-20210210112028263-1452821321.png) 黃色列表獨有,紅色元組特有,元組竟然還多了個`s.__getnewargs__()`方法!從表中可以清楚地看到,除了跟增減元素相關的方法之外,元組支援列表的其他所有方法。 # 列表也能拆 既然列表和元組是孿生兄弟,那必然也有共同技能: ```python list_test = [1, 2, 3] a, b, c = list_test ``` ```python >>> divmod(20, 8) (2, 4) >>> t = [20, 8] # 換成列表 >>> divmod(*t) (2, 4) ``` 列表拆包,也是ok的。 # 小結 本文介紹了Python神奇操作元組拆包,藉助`_`佔位符和`*`字首可以進行更加靈活的取值,具名元組實際用的還比較少,不過看一些原始碼是有的。文章最後比較了列表和元組的差異,列表也能拆包。列表(list)、元組(tuple),以及字串(str),都有一個共同操作:切片。 > 參考資料: > > 《流暢的Py