1. 程式人生 > >Python學習4--Python序列及操作

Python學習4--Python序列及操作

文章導讀:
1. 瞭解python中的序列:列表(list)和元組(tuple)
2. 瞭解序列的構建:列表推導和生成器
3. 瞭解序列的操作:切片拼接排序

內建序列型別分類

Python有豐富的序列型別,大致可按兩種標準分類

  1. 按能否存放不同型別的資料
    • 容器序列(可以存放) : list,tuple,collections.deque
    • 扁平序列(不可以) : str,bytes,bytearray,memoryview,array.array
    • 注意:容器序列中存放的是包含的物件的引用,而扁平序列中存放的是值不是引用
  2. 按能否被修改
    • 可變序列(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

列表推導的作用只有一個:生成列表。它的優勢在於可讀性高

,因此要保持簡短,避免濫用列表推導。如果列表推導的語句過長,應該考慮使用for迴圈重寫。

列表推導還可以用於生成兩個或以上可迭代型別的笛卡爾積。

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,忽略大小寫。