深挖 Python 元組 pt.2
哈嘍大家好,我是咸魚
在《深挖 Python 元組 pt.1》中我們了解 Python 元組的一些概念(索引和切片等),以及如何創建元組,最重要的是我們還介紹了元組的不可變特性
那么今天我們來繼續深挖 Python 元組
打包&解包
在 python 中,元組可以被打包(packing )和解包(unpacking )
例如,point = x, y, z 將會把 x, y 和 z 的值打包到 point 中,于是創建了一個新元組
圖片
我們還可以執行反向操作(解包),將元組 point 的值解包為適當數量的變量
圖片
可以看到,x, y, z = point 神奇地將point的內容解壓縮為三個變量。注意,值按順序轉到變量。(第一個值歸第一個變量,第二個值歸第二個變量,依此類推)
Python 3.5 擴展了元組解包語法,以處理各種可迭代對象
所以不單單元組可以解包,可迭代對象也可以解包
在常規解包中,變量的數量必須與要解包的值的數量相匹配。否則會報錯
圖片
解包最常見的用例就是利用解包在變量之間交換值
沒有解包的話使用常規賦值在兩個變量之間交換值,必須使用臨時變量
圖片
通過解包來交換變量值
圖片
解包還有一個用處是并行分配,比如說下面的操作:我們在進行賦值時需要知道對應的索引
圖片
如果通過解包來實現,則無需使用索引。這樣能使代碼更易閱讀和理解,且不易出錯
圖片
Python 還有一個打包和解包運算符 ( * ),我們可以使用它讓解包(打包)操作更加靈活
例如當左邊的變量數和右邊元組的元素數量不匹配時,可以使用 * 使得單個變量接收多個值
圖片
關于這個操作符的更多用法,可以看我之前的文章:《python 星號 * 還能這么用》
函數返回元組
在某些情況下,需要從函數返回多個值。所以可以構建一個帶有逗號分隔的一系列參數的 return 語句,這樣返回的是一個元組
我們還可以使函數返回值是列表,這樣需要我們顯式地使用方括號來構建列表
內置 divmod() 函數是返回多個值的函數的一個很好的例子。該函數接受兩個數字,并在執行整數除法時返回一個包含商和余數的元組:
圖片
又或者我打算寫一個函數,這個函數返回一組數的最大值和最小值
圖片
可以看到函數的返回值有兩個:最大值、最小值。當用逗號分隔一系列值時,將創建一個元組。因此,此函數返回一個 tuple 對象
深拷貝&淺拷貝
當需要轉換數據時,通常需要復制對象,同時保持原始數據不變。在處理可變數據類型(如列表和字典)時,副本非常有用
副本可以在不影響原數據的情況下對數據進行更改
- 直接賦值
我們先來看一個例子
圖片
可以看到,student_info、 student_profile 是對同一元組對象的引用。所以, student_profile 是 的 student_info 別名而不是副本
- 淺拷貝
copy 模塊中的 copy() 函數生成等效結果
圖片
可以看到,兩個變量student_info、 student_profile 都包含對同一元組對象和相同元素的引用
上面的元組里面包含了一個列表元素,我們知道列表是可變的,我們來試著更改一下
圖片
可以看到,student_profile 更改會影響 student_info 中的原始數據
- 深拷貝
下面的例子中, student_info 通過 deepcopy() 函數制作了student_profile
圖片
可以看到,兩個變量student_info、 student_profile 指向的元組對象不是同一個
如果我們對里面的列表元素進行更改
圖片
可以看到,對student_profile 的修改不會影響 student_info 中的數據
總結一下:
- 元組的淺拷貝不會創建一個新的對象(副本)。
- 元組的深拷貝創建一個新的元組對象
- 對于元組內的不可變元素,它們仍然會共享相同的內存地址
- 對于元組內的可變元素,則是創建了一個新的對象,不共享內存地址
其他操作
- 元組拼接和重復
在 Python 中連接兩個元組,可以使用加號運算符 ( + )
圖片
需要注意的是,+ 左右兩邊必須都是元組,即只能將元組跟元組拼接。如果元組跟列表或其他對象拼接的話,會報錯
圖片
元組使用重復運算符 ( * )將元素克隆多次
圖片
- 元組反轉和排序
內置 reversed() 函數將序列作為參數,并返回一個迭代器,該迭代器以相反的順序從輸入序列生成值。
圖片
使用元組作為參數進行調用 reversed() 時,將獲得一個迭代器對象,該對象以相反的順序生成項
如果要對元組進行排序,可以使用內置 sorted() 函數,該函數將值的可迭代對象作為參數并以列表形式返回排序后的值
圖片
如果元組里面的元素數據類型不一致(異構數據),則無法排序