歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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

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

一、Python中序列的分類


Python中的序列主要以下幾種類型:

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

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

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

二、Python中序列支持的操作


1.通用序列操作

這裡說的通用序列操作是指大部分可變序列與不可變序列都支持的操作。一般操作包括 增、刪、改、查,但是這裡說的是包括不可變序列也支持的通用操作,因此只能是“查”操作。

符號說明:

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

序列通用操作及結果說明:

操作結果 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),但是不會拷貝任何數據且返回的索引值是相對於序列的開始位置而不是相對於切片的開始位置。

3.可變序列類支持的型操作

這裡來說下可變序列類型支持,而不可變序列類型不支持的操作。在序列通用操作中主要說明的是“查”操作,這裡要說的是可變序列的 "增"、“刪”、“改”操作。

符號說明:

符號說明 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是一樣的。

不可變序列支持的操作

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

三、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)

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

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)


Copyright © Linux教程網 All Rights Reserved