Python數據類型之「序列概述與基本序列類型(Basic Sequences)」

序列是指有序的隊列,重點在"有序"。python

1、Python中序列的分類


Python中的序列主要如下幾種類型:數組

  • 3種基本序列類型(Basic Sequence Types):list、tuple、range
  • 專門處理文本的附加序列類型(Text Sequence Types):str
  • 專門處理二進制數據的附加序列類型(Binary Sequence Types): bytes、bytearray、memoryview

按照序列是否可被改變分類:app

  • 可變序列: list
  • 不可變序列:tuple、str

2、Python中序列支持的操做


1.通用序列操做

這裏說的通用序列操做是指大部分可變序列與不可變序列都支持的操做。通常操做包括 增、刪、改、查,可是這裏說的是包括不可變序列也支持的通用操做,所以只能是「查」操做。函數

符號說明:測試

符號 說明
s,t 表示相同類型的序列
n,i,j,k 表示整數數值
x 表示序列s中知足條件約束的任意類型的元素
in(被包含) 和 not in 具備與比較操做相同的優先級
+(鏈接)和*(重複) 具備與相應數字操做相同的優先級。

序列通用操做及結果說明:code

操做 結果
x in s 若是序列s中包含x對象則返回True,不然返回False
x not in s 若是序列s中不包含x對象則返回True,不然返回True
s + t 對序列s和序列t作鏈接操做
s * n 或 n * s 等價於 n個s相加
s[i] 表示序列s的第i個元素,i初始值爲0
s[i:j] 序列s從下標i到下標j的切片(包含s[i],但不包含s[j])
s[i:j:k] 序列s從下標i到下標j的切片,且步長爲k
len(s) 序列s的長度
min(s) 序列s中的最小值
max(s) 序列中的最大值
s.index(x[, i[, j]]) x在序列s中從下標i開始到下標j以前範圍內第一次出現的位置
s.count(x) x在序列s中出現的總次數

說明:對象

a) 對於序列來講,其元素的數字類型是不作嚴格區分的,如True=1=1.0,False=0=0.0;排序

b) 相同類型的序列也支持比較操做,特別是tuple和list是經過比較對應元素的字典順序來進行比較的。這意味着要判斷兩個序列相等,就須要這兩個序列中的每一個元素都相等,而且這兩個序列必須是相同類型且長度相等。索引

注意:接口

a) 雖然in 和 not in操做只用於通常狀況下的簡單容器測試,但一些專用序列(如str,bytes和bytearray)也用於子序列測試。

>>> "ll" in "hello"
True

b) 若是s * n中n小於0,則n會被當作0看待;s * 0的結果是產生一個與s相同類型的空序列。

>>> "ss" * -2
''
>>> ["Tom", "Peter", "Jerry"] * -2
[]
>>> ("Tom", "Peter", "Jerry") * -2
()

c) 對於s * n操做,s序列中的元素沒有被複制,他們只是被引用了屢次。

>>> lists = [['a']] * 3
>>> lists
[['a'], ['a'], ['a']]
>>> lists[0].append('b')
>>> lists
[['a', 'b'], ['a', 'b'], ['a', 'b']]

d) 對於序列的切片操做s[i:j[:k]],若是i或j負數,則索引是相對於字符串的尾部來計算的。若是i是負數,則i至關於len(s)+i,若是j是負責,則j至關於len(s)+j。

>>> [0,1,2,3,4,5,6,7,8,9][-1]
9
>>> [0,1,2,3,4,5,6,7,8,9][-5:-1]
[5, 6, 7, 8]
>>> [0,1,2,3,4,5,6,7,8,9][1:-1]
[1, 2, 3, 4, 5, 6, 7, 8]

e) 仍是對於序列的切片操做s[i:j[:k]],其中i與j的值有以下幾種狀況:

  • 若是i或j爲負數,則先替換爲len(s)+i或len(s)+j再進行以下比較;
  • 若是i或j大於len(s),則其值取len(s);
  • 若是i被忽略或爲None,則其值取0;
  • 若是j被或略或爲None,則其值取len(s);
  • 若是i的值比j大,則切片結果爲空序列。
>>> s = (0,1,2,3,4,5,6,7,8,9)
>>> len(s)
10
>>> s[6:12]
(6, 7, 8, 9)
>>> s[:5]
(0, 1, 2, 3, 4)
>>> s[5:]
(5, 6, 7, 8, 9)
>>> s[9:5]
()

若是步長k被指定,則切片結果中的元素爲i,i+k,i+2k,i+3k,...到j的前一個元素中止。k的值不能爲0,若是k爲None則其值取1。

>>> s[1::2]
(1, 3, 5, 7, 9)
>>> s[0::2]
(0, 2, 4, 6, 8)
>>> s[0::0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero

f) 鏈接不可變序列時老是會致使產生一個新的對象。這意味着經過重複鏈接構建序列將會在在總序列長度中具備二次運行時成本。要得到線性運行成本,必須切換到如下選項之一:

  • 若是鏈接str對象,能夠構建一個列表,並在結尾使用str.join()方法進行鏈接;或者寫入io.String()實例並在完成時檢索其值;
  • 若是鏈接bytes對象,能夠相似地使用bytes.join()方法或io.BytesIO,或者可使用bytearray對象進行就地鏈接;bytearray是能夠變的,而且具備有效的覆蓋分配機制;
  • 若是鏈接tuple對象,請使用擴展list的方式替代;
  • 對於其餘類型,請查看相關類文檔;

g) 一些序列類型(例如 range)僅支持遵循特定模式的元素序列,所以不支持序列的鏈接和重複操做。

h) 對於s.index(x[, i[, j]])操做,當在序列s中找不到x元素時,index會拋出ValueError。另外,附加參數i,j容許對該序列的子序列進行有效的查找,這大體至關於s[i,j].index(x),可是不會拷貝任何數據且返回的索引值是相對於序列的開始位置而不是相對於切片的開始位置。

2. 可變序列類支持的型操做

這裏來講下可變序列類型支持,而不可變序列類型不支持的操做。在序列通用操做中主要說明的是「查」操做,這裏要說的是可變序列的 "增"、「刪」、「改」操做。

符號說明:

符號 說明
s 表示一個可變序列類型的實例
t 表示任何一個可迭代對象
x 表示序列s中知足條件約束的任意類型的元素(例如,bytearray只接受知足0 <= x <=255約束的整型值)

可變序列支持的操做及結果說明:

操做 結果
s[i] = x 將序列s中小標爲i的元素用x替換
s[i:j] = t 將序列s中從i到j的切片用可迭代對象t的內容替換
s[i:j:k] = t s[i:j:k]中的元素用可迭代對象t的內容替換
s *= n 更新序列s爲s的n次重複的結果
del s[i:j] 刪除序列s中從i到j的切片,等價於 s[i:j] = []
del s[i:j:k] 從序列s中刪除s[i:j:k]中的元素
s.pop() / s.pop(i) 獲取序列s中下標爲i的元素,並從序列s中刪除該元素;i默認爲-1,即默認刪除並返回序列s的最後一個元素
s.remove(x) 從序列s中移除第一個等於x(即:s[i] == x )的元素;若是x在序列s中不存在,則會拋出ValueError
s.clear() 移除序列s中的全部元素,等價於 del s[:]
s.append(x) 將x追加到序列s的末尾,等價於 s[len(s):len(s) = [x]]
s.extend(t) or s+=t 將可迭代對象t中的元素拼接到序列s的末尾,大部分時候等價於 s[len(s):len(s)] = t
s.insert(i,x) 在序列s中下標爲i的位置插入x
s.copy() 建立一個序列s的淺拷貝,等價於 s[:]
s.reverse() 反轉序列s中元素的位置,該方法直接對序列s自己作修改(能夠節約空間),不會返回被反轉後的序列

注意:

a) 可變序列的clear()和copy()方法是Python 3.3中新加的方法,是爲了與dict、set這些不支持切片操做的容器所提供的接口保持一致性。

b) 對於 s *= n操做,若是n小於0或等於0,序列s將被清空;另外若是n大於1,序列s並無被複制,它們只是被引用了屢次,這與序列通用操做中的s * n是同樣的。

3. 不可變序列支持的操做

不可變序列類型一般實現而可變序列沒有實現的惟一操做是對內建hash()方法的支持。對內建hash()的支持容許不可變序列(例如tuple)用做dict的鍵並存儲在set和frozenset的實例中。若是嘗試hash一個包含不可被hash的數據的不可變序列會致使TypeError錯誤。

3、Python中的基本序列(basic sequences)

Python中的基本序列類型包括: list、tuple、range,而str屬於特殊序列類型,專門用於處理文本序列,這個後面單獨進行說明。

1. List(列表)

Python中的列表是可變序列,一般用於存儲相同類型的數據集合,固然也能夠存儲不一樣類型數據。Python中的列表表現形式有點像其餘語言中的數組:列表中的元素是用方括號[]括起來,以逗號進行分割。

list類構建函數

class list([iterable])  # 這裏的方括號表示iterable是可選項

list的建立方式

  • 使用方括號,用逗號分隔各條目:[],['a'], [a, b, c]
  • 使用類型構造函數:list(), list(iterable)
  • 使用列表生成式:[x for x in iterable]

列表構造函數list(iterable)會建立一個與可迭代對象iterable中的條目及條目順序都相同的列表。可迭代對象iterable能夠是一個序列(sequence)、一個支持迭代操做的容器(container),也能夠是一個迭代器對象(iterator object)。若是iterable已是一個list,則建立一個copy並返回,相似於iterable[:]。若是沒有指定參數,列表構造函數會建立一個新的空list, []。

建立list示例:

>>> list1 = []  # 空列表
>>> list1
[]
>>> list2 = ["Tom", "Jerry", "Lucy", "Peter"]  # 非空列表
>>> list2
['Tom', 'Jerry', 'Lucy', 'Peter']
>>>
>>> list3 = list()  # 列表構造函數建立空列表
>>> list3
[]
>>> list4 = list(list2)
>>> list4
['Tom', 'Jerry', 'Lucy', 'Peter']
>>>
>>> list5 = [x for x in list2]  # 列表生成式
>>> list5
['Tom', 'Jerry', 'Lucy', 'Peter']

list實現了全部通用(common)序列操做和可變序列(mutable sequence)操做,此外,list還提供了一些附加方法。

list通用序列操做示例

>>> s = [1, 2, 3, 'a', 'b', 'c']
>>> 1 in s  # 包含判斷
True
>>> 1.0 in s  # 數字不嚴格區分類型(1==1.0==True)
True
>>> 1 not in s  # 不包含判斷
False
>>> s + ['d', 'e', 'f']  # 拼接操做
[1, 2, 3, 'a', 'b', 'c', 'd', 'e', 'f']
>>> s * 2  # 重複2次
[1, 2, 3, 'a', 'b', 'c', 1, 2, 3, 'a', 'b', 'c']
>>> s[3]  # 獲取下標爲3的條目
'a'
>>> s[3:6]  # 獲取序列s的切片,下標分別爲 3,4,5
['a', 'b', 'c']
>>> s[1:6:2]  # 獲取序列s的切片,步長爲2,下標分別爲 1,3,5
[2, 'a', 'c']
>>> len(s)  # 獲取序列長度
6
>>> min(s)  # min()和max()的參數中,數據類型須要有可比性
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() < int()
>>> max([1, 2, 3, 4.0, 5.0])
5.0
>>> min([1, 2, 3, 4.0, 5.0, False])
False
>>>
>>> [1, 2, 3, 4, 2, 5, 6, 3, 2].index(2)  # 獲取2在序列s中第一次出現的下標位置
1
>>> [1, 2, 3, 4, 2, 5, 6, 3, 2].index(2, 3)  # 獲取序列s從下標3開始查找2第一次出現的下標位置
4
>>> s.count(2)  # 統計2在序列s中出現的次數
1
>>> [1, 2, 3, 4, 2, 5, 6, 3, 2].count(2)
3
>>> len([1, 2, 3, 4, 5])  # 獲取序列長度
5

list可變序列操做示例

>>> s = [1, 2, 3, 4]
>>> s
[1, 2, 3, 4]
>>> s.append(5)  # 向list末尾追加一個條目
>>> s
[1, 2, 3, 4, 5]
>>> s.insert(0,0)  # 向list開始位置插入一個條目
>>> s
[0, 1, 2, 3, 4, 5]
>>> s.extend([6, 7, 8, 9])  # 擴展list, 向list末尾拼接多個條目
>>> s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> s[9] = 99  # 將list中下標爲9的條目替換爲99
>>> s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 99]
>>> s[6:9] = ['a', 'b']  # 將list中範圍爲從6到9(不包含9)的切片替換爲['a', 'b']
>>> s
[0, 1, 2, 3, 4, 5, 'a', 'b', 99]
>>> s[6:10]=['A','B']  # 同上,此處10爲list的長度,表示切片範圍是到list末尾的
>>> s
[0, 1, 2, 3, 4, 5, 'A', 'B']
>>> s.pop()  # 移除list末尾的條目
'B'
>>> s
[0, 1, 2, 3, 4, 5, 'A']
>>> s.pop(5)  # 移除list中下標爲5的條目
5
>>> s
[0, 1, 2, 3, 4, 'A']
>>> s.remove('A')  # 移除list中的指定條目'A'
>>> s
[0, 1, 2, 3, 4]
>>> del s[1:5:2]  # 刪除list中下標爲 1,3 的條目
>>> s
[0, 2, 4]
>>> s.reverse()  # 將list中元素位置進行反轉,list自己發生改變
>>> s
[4, 2, 0]
>>> s.copy()  # list淺拷貝,list自己不發生改變
[4, 2, 0]
>>> s
[4, 2, 0]
>>> s *= 2  # 至關於 s = s * 2
>>> s
[4, 2, 0, 4, 2, 0]

list支持的額外操做

sort(*, key=None, reverse=None)

此方法僅使用 < 符號進行列表項目之間的比較,即默認對列表進行升序排序。排序過程當中的異常不會被捕獲,也就是說若是任何比較操做失敗,整個排序操做將失敗,而且列表可能保留部分已修改狀態。

sort()只能經過關鍵字(僅限關鍵字參數)傳遞的兩個參數以下:

  • key : 指定一個函數,該函數用於從每一個列表元素提取用於進行比較操做的鍵,如key = str.lower。列表中每個條目對應的鍵都會被計算一次,而後用於整個排序過程。默認值None表示列表條目將會被直接排序,而不會計算出一個單獨的用於比較的鍵值。
  • reverse : 是一個布爾值,若是其值爲True,則列表中的元素將會按照比較方法的反序進行排序。

說明:

sort()方法會直接修改list,這在對大列表進行排序時能夠節約空間;該方法的反作用是不會返回排序後的list,可使用sorted()顯示請求一個新的排序後的list實例;

sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list

sort()方法保證穩定性。若是能保證兩個比較至關的元素不會改變相對位置,那麼這個排序就是穩定的,這有助於經過多個條件進行排序,好比 先按部門排序,而後再按工資級別排序。

CPython實現細節:當一個列表正在被排序時,若是嘗試修改或檢測列表,效果是列表未定義。Python的C實現使得列表在持續時間內顯示爲空,而且若是它檢測到列表在排序期間已發生改變,則會拋出ValueError錯誤。

>>> s = ['A', 'b', 'C', 'd', 'e']
>>> s.sort()
>>> s
['A', 'C', 'b', 'd', 'e']
>>> s.sort(key=str.lower)
>>> s
['A', 'b', 'C', 'd', 'e']
>>> s.sort(key=str.upper)
>>> s
['A', 'b', 'C', 'd', 'e']
>>> s.sort(key=str.upper, reverse=True)
>>> s
['e', 'd', 'C', 'b', 'A']
>>> s.sort(reverse=True)
>>> s
['e', 'd', 'b', 'C', 'A']
>>> sorted(s)  # sorted()能夠對任何可迭代對象進行排序,不會對原數據進行修改且會返回一個排序後的實例
['A', 'C', 'b', 'd', 'e']
>>> s
['e', 'd', 'b', 'C', 'A']
>>>

2.Tuple(元祖)


Tuple是不可變序列,一般用於存儲異構數據集合,例如由內置函數enumerate()產生的2元組。元祖還用於同構數據的不可變序列的狀況,例如容許在set或dict實例中存儲。

tuple類構建函數

class tuple([iterable])  # 此處的方括號表示iterable是可選參數

tuple的構建方式

  • 使用一對小括號表示空元組:()
  • 對單個元組要使用逗號結尾:a, 或 (a, )
  • 多個條目要使用逗號分隔:a, b, c 或 (a, b, c)
  • 使用內置函數tuple() 或 tuple(iterable)

tuple構造函數tuple(iterable)會建立一個與可迭代對象iterable中的條目及條目順序都相同的元祖。可迭代對象iterable能夠是一個序列(sequence)、一個支持迭代操做的容器(container),也能夠是一個迭代器對象(iterator object)。若是iterable已是一個tuple,則直接返回這個tuple。若是沒有指定參數,元組構造函數會建立一個新的空tuple, ()。

說明:

實際上,是逗號產生了一個元祖,而不是小括號。除了空元組的情形或者須要避免語法模糊的時候外,小括號是可選的。例如f(a, b, c)是具備3個參數的函數調用,而f((a, b, c))是以3元祖做爲惟一參數的函數調用。

tuple建立示例

>>> 1,  # 有逗號結尾表示元組
(1,)
>>> (1, )
(1,)
>>> 1  # 沒逗號結尾表示數字
1
>>> (1)
1
>>> ()  # 空數組
()
>>> tuple()
()
>>> tuple([1, 2, 4])  # 非空數組
(1, 2, 4)
>>> 1, 2, 3
(1, 2, 3)
>>> (1, 2, 3)
(1, 2, 3)

tuple是不可變序列,它支持全部通用序列操做(與list一致,此處再也不給出示例),但不支持可變序列操做。

3.range(範圍)

range類型表示一個不可變的數字序列,一般用於在for循環中循環特定次數。

range類構建函數

class range(stop)
class range(start, stop[, step])
    start:表述數字序列開始值,若是該參數沒有被提供則值爲0
    stop: 數字序列結束值
    stop: 數字序列步長,若是該參數沒有被提供則值爲1

關於start、stop、step參數值的說明:

  • 這些參數必須是整型值(內建 int或者任何實現了__index__ 特殊方法的任意對象)
  • 若是start參數被忽略,其默認值爲0;若是step參數被忽略,其默認值爲1;若是step爲0,則會拋出ValueError錯誤
  • 若是step參數爲正數,那麼range類型對象r的內容公式爲:r[i] = start + step*i,約束條件爲:i >= 0 且 r[i] < stop
  • 若是step參數爲負數,那麼range類型對象r的內容公式仍然爲:r[i] = start + step*i,可是約束條件爲:i >= 0 且 r[i] > stop
  • 若是r[0]不知足約束條件,range對象的值將爲空
  • range對象能夠包含絕對值大於sys.maxsize的值,可是某些功能(如:len())可能會引起OverflowError

range示例

>>> list(range(10))  # start沒有指定,默認值爲0,即start=0,end=10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1,11))  # start=1, end=11
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 11, 2))  # 要指定step就必需要指定start
[0, 2, 4, 6, 8, 10]
>>> list(range(0, -10, -1))  # step爲負數
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0))
[]
>>> list(range(10, 5))  # 若是end < start ,則range對象爲空
[]

這裏須要注意一下,Python 2.x中的range()函數返回的是一個list類型,而Python 3.x中的range()函數返回的是一個range類型。

Python 2.x

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

Python 3.x

>>> range(10)
range(0, 10)

range實現了除鏈接(concatenation)和重複(repetition)以外的全部通用序列操做,這是因爲range對象只能表示遵循嚴格模式的序列,而鏈接和重複操做一般會違反這個模式。

range相對於常規list和tuple的優勢在於:不管它表示的範圍的大小是多少,它始終佔用相同(小)量的內存。這是由於它只須要存儲 start、end和step這3個值,而後根據須要計算各個條目和子範圍。

說明:

測試range對象是否相等與序列同樣經過 == 和 != 進行比較,也就是說,若是兩個range對象表示相同值的序列就被認爲是相等的。須要注意的是,比較相等的兩個range對象可能具備不一樣的start、end、step參數值,例如 (0) == (2, 1),又例如 (0, 3, 2) == (0, 4, 2)

相關文章
相關標籤/搜索