Python學習4--Python序列及操作
文章導讀:
1. 瞭解python中的序列:列表(list)和元組(tuple)
2. 瞭解序列的構建:列表推導和生成器
3. 瞭解序列的操作:切片、拼接、排序
內建序列型別分類
Python有豐富的序列型別,大致可按兩種標準分類
- 按能否存放不同型別的資料
- 容器序列(可以存放) : list,tuple,collections.deque
- 扁平序列(不可以) : str,bytes,bytearray,memoryview,array.array
- 注意:容器序列中存放的是包含的物件的引用,而扁平序列中存放的是值不是引用
- 按能否被修改
- 可變序列(MutableSequence) :list,bytearray,array.array,collections.deque,memoryview
- 不可變序列 :tuple,str,bytes
構建序列:列表推導和生成器表示式
對於序列構建,有過程式設計基礎的可能比較熟悉生成器表示式。例如:
tuple(i for i in range(4))
array.array('I',(i for i in range(4)))
但是在Python中,提供了一種更為簡介的方式,就是列表推導。
列表推導的形式如下:
symbols = '$¥&@'
codes = [ord(symbol) for symbol in symbols] #把字串轉化為Unicode
列表推導的作用只有一個:生成列表。它的優勢在於可讀性高
列表推導還可以用於生成兩個或以上可迭代型別的笛卡爾積。
colors = ['red','blue','green']
sizes = ['S','M','L']
tshirts = [(color,size) for color in colors for size in sizes]
元組:不僅僅是不可變列表
剛開始學習Python時,對元組的概念可能僅僅停留在“不可變列表”。但其實元組有兩種公用:記錄和不可變列表。
我們首先談談元組的記錄功能,元組用於沒有欄位名的記錄,元組中的每個元素都存放了記錄中一個欄位的資料
元組拆包
而資料的價值在於使用,因此有了元組拆包,拆包讓元組完美的被當作記錄來使用。最簡單易懂的拆包形式就是平行賦值,也就是把一個可迭代物件裡的元素一併賦值到對應的變數中。例如:
info = (33.9425,-118.408056)
latitude,longtitude = info #元組拆包
?思考1:拆包時,不是需要所有資料,那怎麼辦?
佔位符和*很好的處理了這種情況,佔位符用於排除無關資訊,而*用來處理剩下的元素,其實在很多程式語言中, 都有類似*args來獲取不確定數量的引數。
import os
_,filename = os.path.split('/home/hzy/test.txt') #filename:test.txt
## 注意:python3.5一下不支援*args表示式
a,b,*rest = range(5) #rest:[2,3,4]
a,*body,c,d = range(5) #rest:[1,2]
元組拆包是支援巢狀式的,例如像(a,b,(c,d))形式,只需對應的型別正確。
具名元組
?思考2:元組作為記錄來說,似乎設計的很好了,但還是少了一個功能:給記錄中欄位命名。
collections.namedtuple函式解決了這一問題,它可以構建一個帶欄位名的元組和一個有名字的類。
from collections import namedtuple
City = namedtuple('City','name country population coordinates')
tokyo = City('Tokyo','Japan','36.933',(35.689722,139.691667))
具名元組有一些自己專有的屬性。常有的有:
1. _fields屬性:包含類所有欄位名
2. _make():接受一個可迭代物件生成這個類的一個例項
3. _asdict():把具名元組以collections.OrderedDict的形式返回
作為不可變列表的元組
我們再來談元組的不可變性,我們可以根據下表瞭解元組和列表的區別
TODO
?思考3:上表中,為什麼元組具有拼接功能,而不具有就地拼接功能。
切片
在Python中,list,tuple,str等序列都支援切片。切片的形式為s[start:stop:step],step可以為負值,負值意味著反向取值。而實際切片時,是呼叫了seq.__getitem__(slice(start,stop,step))特殊方法.
?思考4:為什麼切片和區間會忽略最後一個元素
這是因為在Python和其他語言中,都是以0作為起始下標。
python還支援多維切片,在後面的4.2的numpy.ndarray會提到。
python也支援給切片賦值,例如:
l = list(range(10)) #l [0,1,2,3,4,5,6,7,8,9]
l[2:5] = [20,30] #l [0,1,20,30,5,6,7,8,9]
del l[5:7] #l[0,1,20,30,5,8,9]
l[3::2] = [11,22] #l[0,1,20,11,5,22,9]
拼接
Python序列支援+和操作,注意,* 這兩種拼接都會構建一個新的序列。 **
TODO
Python也支援增量賦值+=和*=。
+=實際上呼叫的特殊方法是__iadd__(就地加法),但如果序列沒有實現該方法,會退一步呼叫__add__。在Python中,如果一個方法對物件進行的是就地改動,那它就會返回None,好讓呼叫者知道傳入的引數發生改變,但並未產生新的物件。
*=也同於+=,呼叫的是__imul__。
基於上訴原因,對於可變序列來說,增量賦值不會產生新的物件;而對於不可變序列來說,因為不支援就地改動,因此使用增量賦值時實際呼叫的是如__add__,會產生新的物件。這也解釋了思考3。
排序
list.sort為就地排序,與上文提到的就地改變契合,因此不會生成新的列表。
而內建函式sorted,會新建一個列表作為返回值。
不管是list.sort,還是sorted。都有兩個可選關鍵字引數。
1. reverse:是否降序輸出。預設為False。
2. key:根據關鍵字改變排序方式。如key=len,根據長度排序。key=str.lower,忽略大小寫。