1、序列類型 1.1 元組 1.1.1 元組的建立 1.1.2 元組索引和分區 1.1.3 元組方法 1.1.4 元組運算子 1.1.5 元組的刪除 1.1.6 無關閉分隔字元 1.2 命名的元組 1.3 列表 1.3.1 列表的建立 1.3.2 清單索引和分區 1.3.3 列表方法 1.3.4 拆分操作符 1.3.5 刪除 1.3.6 列表內涵 2、集合類型 2.1 集合 2.1.1 集合的建立 2.1.2 集合方法與操作符 2.1.3 集合內涵 2.2 固定集合 3、映射類型 3.1 字典 3.1.1 字典的建立 3.1.2 字典方法 3.1.3 字典內涵 3.2 預設字典 3.3 有序字典 4、組合資料類型的迭代與複製 4.1 迭代子、迭代操作與函數 4.2 組合類別型的複製
本章我們將學習如何使用Python的組合資料類型將資料項目集合在一起,以便在程式設計時有更多的選項。
1、序列類型
Python提供了5中內建的序列類型:bytearray、bytes、list、str與tuple,序列類型支援成員關係操作符(in)、大小計算函數(len())、分區([]),並且是可可迭代的。 1.1 元組
元組是個有序序列,包含0個或多個對象引用,使用小括弧包裹。元組是固定的,不能替換或刪除其中包含的任意資料項目。 1.1.1 元組的建立
使用()建立一個元組: 括弧內不包含內容,則建立一個空元組 括弧內包含使用逗號分隔的資料項目,建立一個非空元組
也可以使用tuple()建立一個元組: 不指定參數時,返回一個空元組 使用tuple作為參數時,返回該參數的淺拷貝 其他參數時,嘗試將給定的對象轉換為tuple類型 1.1.2 元組索引和分區
| 文法 |
描述 |
| tup[1] |
讀取第二個元素 |
| tup[-2] |
反向讀取;讀取倒數第二個元素 |
| tup[1:] |
截取元素 |
tup = ('first', 5, 'white', 'dog')print(tup[1])print(tup[-2])print(tup[1:])[out]5white(5, 'white', 'dog')
1.1.3 元組方法
元組只提供兩種方法:
| 文法 |
描述 |
| t.count(x) |
返回對象x在元祖t中出現的次數 |
| t.index(x) |
返回對象x在元組t中出現的最左邊位置 |
tup = ('1', 'first', '1', '1', '2')print('count of "1":',tup.count('1'))print('index of "2":',tup.index('2'))[out]count of "1": 3index of "2": 4
1.1.4 元組運算子
與字串一樣,元組之間可以使用 + 號和 * 號進行運算。這就意味著他們可以組合和複製,運算後會產生一個新的元組。
| 文法 |
描述 |
| len(t) |
返回元組t中元素個數 |
| + |
串連 |
| * |
複製 |
| in |
元素是否存在 |
| for … in …: |
迭代 |
比較子 <、<=、>、>=、==、!= |
逐項進行比較 |
1.1.5 元組的刪除
元組中的元素值是不允許刪除的,但我們可以使用del刪除整個元組:
tup = ('python', 'hello', 1997, 2000);print(tup)del tupprint("After deleting tup : ")print(tup)[out]('python', 'hello', 1997, 2000)After deleting tup : ---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-1-a12bbf13863f> in <module>() 4 del tup 5 print("After deleting tup : ")----> 6 print(tup)NameError: name 'tup' is not defined
1.1.6 無關閉分隔字元
當元組出現在二進位操作符的左邊或出現在unary語句的右邊時,可以不使用圓括弧。
a,b = (1,2) # left of binary operatorfor x,y in ((1,2),(3,4),(5,6)): # left of binary operator print(x,y)del a,b # right of unary statementdef f(x): return x,x**2 # right of unary statement
1.2 命名的元組
命名的元組(namedtuple)與普通元組一樣,有相同的表現特徵,其添加的功能就是可以根據名稱引用元組中的項。
collections模組提供了namedtuple()函數,用於建立自訂的元組資料類型。該函數的第一個參數是想要建立的自訂元組資料類型的名稱,第二個參數是一個字串,其中包含使用空格分隔的名稱,每個名稱代表該元祖資料類型中的一項。該函數返回一個自訂的類,可用於建立命名的元組。
import collectionsSale = collections.namedtuple('Sale', 'productid customerid data quantity price')sales = list()sales.append(Sale(432,921,"2018-04-01",3,8.2))sales.append(Sale(543,879,"2018-03-31",6,8.1))print(sales)[out][Sale(productid=432, customerid=921, data='2018-04-01', quantity=3, price=8.2), Sale(productid=543, customerid=879, data='2018-03-31', quantity=6, price=8.1)]
這裡我們建立了包含兩個Sale項的列表,我們可以使用索引位置來引用元組中的項,也可以使用名稱進行引用,後者正式命名的元組的特點:
total = 0for sale in sales: total += sale.quantity * sale.priceprint('Total ¥{0:.2F}'.format(total))[out]Total ¥73.20
1.3 列表
列表是包含0個或多個對象引用的有序序列,支援與字串以及元組一樣的分區與步距文法,列表是可變的,因此我們可以對列表中的項進行刪除或替換,插入、替換或刪除列表中的分區也是可能的。 1.3.1 列表的建立
使用[]建立一個元組: 括弧內不包含內容,則建立一個空列表 括弧內包含使用逗號分隔的資料項目,建立一個非空列表
也可以使用list()建立一個列表:
不指定參數時,返回一個空列表
使用list作為參數時,返回該參數的淺拷貝
其他參數時,嘗試將給定的對象轉換為list類型
1.3.2 清單索引和分區
| 文法 |
描述 |
| lst[1] |
讀取第二個元素 |
| lst[-2] |
反向讀取;讀取倒數第二個元素 |
| lst[1:] |
截取元素 |
lst = ['first', 5, 'white', 'dog']print(lst[1])print(lst[-2])print(lst[1:])[out]5white[5, 'white', 'dog']
1.3.3 列表方法
下表中,L為列表。
| 文法 |
描述 |
| L.append(x) |
將資料項目x追加到L的末尾 |
| L.count(x) |
統計元素x在L中出現的次數 |
L.extend(m) L += m |
將iterable m的項追加到L的末尾 |
| L.index(x, start, end) |
返回資料項目x在L中(或L的start: end分區中)最左邊出現的索引位置,如果沒找到x,則產生ValueError異常 |
| L.insert(i, x) |
在索引位置i處插入元素x |
| L.pop() |
移除L最右邊的資料項目,並返回該元素的值 |
| L.pop(i) |
移除L索引位置i處的資料項目,並返回該元素的值 |
| L.remove(x) |
從L中移除最左邊的資料項目x,如果沒找到x產生ValueError異常 |
| L.reverse() |
對L進行反轉 |
| L.sort(…) |
對L進行排序,與內建的sorted()函數一樣,可以接受可選的key與reverse參數 |
L = [5, 'python', (1,2), 5, 'today']L.append(9)print('列表追加項:', L)print('列表中5出現的次數:', L.count(5))L.extend('hello')print('追加迭代器中的項:',L)print('"python"最左邊索引值:', L.index('python'))L.insert(1, 'insert')print('在索引位置1處插入:', L)pop_item = L.pop()print('L末尾資料項目:', pop_item)print('移除末尾資料項目後的結果:', L)L.remove((1,2))print('移除(1,2)後的列表:', L)L.reverse()print('反轉後的列表:', L)[out]列表追加項: [5, 'python', (1, 2), 5, 'today', 9]列表中5出現的次數: 2追加迭代器中的項: [5, 'python', (1, 2), 5, 'today', 9, 'h', 'e', 'l', 'l', 'o']"python"最左邊索引值: 1在索引位置1處插入: [5, 'insert', 'python', (1, 2), 5, 'today', 9, 'h', 'e', 'l', 'l', 'o']L末尾資料項目: o移除末尾資料項目後的結果: [5, 'insert', 'python', (1, 2), 5, 'today', 9, 'h', 'e', 'l', 'l']移除(1,2)後的列表: [5, 'insert', 'python', 5, 'today', 9, 'h', 'e', 'l', 'l']反轉後的列表: ['l', 'l', 'e', 'h', 9, 'today', 5, 'python', 'insert', 5]
1.3.4 拆分操作符
任意可迭代的(列表、元組等)資料類型都可以使用序列拆分操作符進行拆分,即*。用於賦值操作符左邊的兩個或多個變數時,其中一個使用*進行引導,資料項目將賦值給該變數,而所有剩下的資料項目將給帶星號的變數。
first, *rest, last = [1, 2, 3, 4, 5]print(first, rest, last)[out]1 [2, 3, 4] 5
1.3.5 刪除
由於列表是可變的,我們可以對其資料項目進行刪除。
刪除單個資料項目
# 刪除一個資料項目L = [5, 'python', (1,2), 5, 'today']del L[1]print('使用del刪除一項:', L)L = [5, 'python', (1,2), 5, 'today']L.pop(1)print('使用pop刪除一項:', L)[out]使用del刪除一項: [5, (1, 2), 5, 'today']使用pop刪除一項: [5, (1, 2), 5, 'today']
刪除分區
# 刪除分區L = [5, 'python', (1,2), 5, 'today']del L[1:3]print('使用del刪除分區:', L)L = [5, 'python', (1,2), 5, 'today']L[1:3] = []print('使用[]刪除分區:', L)[out]使用del刪除分區: [5, 5, 'today']使用[]刪除分區: [5, 5, 'today']
1.3.6 列表內涵
列表內涵是一個運算式,也是一個迴圈,該迴圈有一個可選的、包含在方括弧中的條件,作用是為列表產生資料項目,並且可以使用條件過濾掉不需要的資料項目,可以使用運算式,也可以使用附加條件。常見文法: [expression for item in iterable] [expression for item in iterable if condition]
在沒有列表內涵時,我們找出1900~1940年之間所有的閏年,可能會這麼寫:
# 普通方法找1900~1940年之間的閏年leaps = list()for year in range(1900, 1940): if (year%4 == 0 and year%100 != 0) or (year%400 == 0): leaps.append(year)print(leaps)[out][1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936]
學習了列表內涵之後我們可以簡化程式:
# 列表內涵找1900~1940年之間的閏年leaps = [year for year in range(1900, 1940) if (year%4 == 0 and year%100 != 0) or (year%400 == 0)]print(leaps)[out][1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936]
兩種方法等效,得到同樣的結果。 2、集合類型
set也是一種組合資料類型,支援成員關係操作符(in)、對象大小計算操作符(len()),並且也是iterable。Python提供了兩種內建的集合類型:可變的set類型,固定的frozenset類型。進行迭代時,集合類型以任意順序提供其資料項目。
只有可雜湊運算的對象可以添加到集合中。所有的內建固定資料類型(比如float、frozenset、int、str、tuple)都是可雜湊運算的,可以添加到集合中。內建的可變資料類型(比如dict、list、set)都不是可雜湊運算的,不能添加到集合中。 2.1 集合
集合是0個或多個對象引用的無序組合。集合是可變的,因此可以很容易的添加和移除資料項目,但是由於其中的項是無序的,因此沒有索引位置的概念,也不能分區或按步距分區。 2.1.1 集合的建立
使用set()建立一個集合: 不指定參數時,返回一個空集合 使用set作為參數時,返回該參數的淺拷貝 其他參數時,嘗試將給定的對象轉換為集合
集合中包含的每個資料項目都是獨一無二的——添加重複的資料項目固然不會引發問題,但是也毫無意義。比如,下面產生的三個集合是一樣的:set(‘apple’)、set(‘aple’)、{‘e’, ‘p’, ‘l’, ‘a’}。鑒於此,集合常用於重複資料刪除的資料項目。比如,x是一個字串列表,在執行x=list(set(x))之後,x中的每個字串都是獨一無二的,存放順序是任意的。 2.1.2 集合方法與操作符
s、t為集合,x為資料項目。
| 文法 |
描述 |
| s.add(x) |
將x添加到s中——如果s中尚未包含x |
| s.clear() |
清空s |
| s.copy() |
返回s的淺拷貝 |
s.difference(t) s-t |
返回一個新集合,其中包含在s中但不在t中的所有資料項目 |
s.difference_update(t) s-=t |
移除每一個在t中但不在s中的項 |
| s.discard(x) |
如果x在s中,則移除x |
s.intersection(t) s&t |
返回一個新集合,其中包含所有同時包含在s和t中的資料項目 |
s.intersection_update(t) s&=t |
使得s包含自身與t的交集 |
| s.isdisjoint(t) |
如果s與t沒有相同的項,返回True |
s.issubset(t) s<=t |
如果s與t相同,或s是t的子集,返回True;使用s |
s.issupset(t) s>=t |
如果s與t相同,或s是t的超集,返回True |
| s.pop() |
返回並移除s中的一個隨機項,如果s為空白,就產生一個KeyError |
| s.remove(x) |
從s中移除x,如果s中不包含x,就產生KeyError |
s.symmetric_difference(t) s^t |
返回一個新集合,其中包含s與t中的每個資料項目,但不包含同時在這兩個集合中的資料項目 |
s.symmetric_difference_update(t) s^=t |
使得s只包含其自身與t的對稱差 |
s.union(t) s|t |
返回一個新集合,其中包含集合s中的所有資料項目以及在t中而不在s中的資料項目 |
s.update(t) s|=t |
將t中每個s中不包含的資料項目添加到集合s中 |
2.1.3 集合內涵
除了調用set()建立集合,或使用集合字面值建立集合外,我們可以使用集合內涵建立集合。集合內涵是一個運算式,也是一個帶有可選條件的迴圈,支援的文法: {expression for item in iterable} {expression for item in iterable if condition} 2.2 固定集合
固定集合是指那種一旦建立就不能修改的集合,只能使用frozenset資料類型函數建立,不帶參數調用時,frozenset()返回一個空的固定集合,帶一個frozenset參數時,將返回改參數的 淺拷貝,對於任何其他類型的參數,都嘗試將給定的對象轉換為一個forzenset。 3、映射類型
映射是鍵-值資料項目的組合,並提供了存取資料項目及其鍵、值的方法。Python3.0支援兩種無序的映射類型——內建的dict類型以及標準庫中的collections.defaultdict類型。Python3.1引入了一種新的、有序的映射類型collections.OrderedDict,該類型是一個字典,與內建的dict有相同的方法和屬性,但在儲存資料項目時以插入順序進行。 3.1 字典
dict是一種無序的組合資料類型,其中包含0個或多個鍵-值對。 3.1.1 字典的建立
可以使用{}建立: 空的花括弧建立一個空的字典 包含一個或多個逗號分隔的索引值對,建立一個非空字典
也可以使用dict()函數建立: 不帶參數,建立一個空的字典 帶有dict類型的參數,返回該參數的淺拷貝 索引值對組合的參數,建立非空字典
字典的索引值是獨一無二的,因此,如果向字典中添加一個已存在的索引值項,實際效果是新值替換舊值。 3.1.2 字典方法
d為字典
| 文法 |
描述 |
| d.clear() |
移除d中所有項 |
| d.copy() |
返回d的淺拷貝 |
| d.fromkeys(s, v) |
返回一個dict,該字典的鍵為序列s中的項,值為None或V |
| d.get(k) |
返回鍵k關聯的值,如果d中不存在k則返回None |
| d.get(k, v) |
返回鍵k關聯的值,如果d中不存在k則返回v |
| d.items() |
返回d中所有(key, value)對的視圖 |
| d.keys() |
返回d中所有鍵的視圖 |
| d.pop(k) |
返回鍵k的關聯值,並移除鍵為k的項,如果k不包含在d中就產生KeyError |
| d.pop(k, v) |
返回鍵k的關聯值,並移除鍵為k的項,如果k不包含在d中就返回v |
| d.popitem() |
返回並移除d中任意一個(key, value)對,如果d為空白就產生KeyError |
| d.setdefault(k, v) |
與d.get()方法一樣,不同之處在於,如果k沒有包含在d中就插入一個鍵為k的新項,其值為None或v |
| d.update(a) |
將a中每一個尚未包含在d中的(key, value)對添加到d中,對同時包含在d與a中的每個鍵,使用a中對應的值替換d中對應的值——a可以是字典,也可以是(key, value)對的一個iterable或關鍵字參數 |
| d.values() |
返回d的所有值的視圖 |
上面提到了“視圖”概念,其相對於通常的iterables有兩個不同點: 如果該視圖引用的字典發生變化,那麼視圖將反映該變化。 鍵視圖與項視圖支援一些類似於集合的操作:
v & x # Intersection v | x # Union v - x # Difference v ^ x # Symmentric difference
註:兩種通過鍵取值方式的比較
我們可以通過d[k] 和 d.get()兩種形式來取值,比如我們進行詞頻統計時,使用words[word]+=1或words[word] = words.get(word, 0) + 1 都可以進行加1操作,但是如果單詞第一次出現,第一種形式會產生KeyValue錯誤,第二種則會正確運行。 3.1.3 字典內涵
字典內涵是一個運算式,也是一個迴圈,該迴圈帶有一個可選條件。文法: {keyexpression: valueexpression for key, value in iterable} {keyexpression: valueexpression for key, value in iterable if condition}
例:
# 使用字典內涵建立字典,其中每個鍵是目前的目錄中檔案的檔案名稱,值則為以位元組計數的檔案夾大小import osfile_sizes = {name: os.path.getsize(name) for name in os.listdir('.')}print(file_sizes)[out]{'.ipynb_checkpoints': 0, '第三章組合資料類型.ipynb': 12387}
3.2 預設字典
預設字典也是一種字典——這種字典包含普通字典所提供的所有操作符與方法,與其不同的是可以對遺失的鍵進行處理。
建立預設字典時,我們可以傳入一個工廠函數,這樣就會為遺失的鍵建立預設值。看下面例子
import collectionswords = collections.defaultdict(int)x = words['a']print(x)[out]0
上面我們建立的預設字典words永遠不會產生KeyError異常,如果遇到沒有的鍵,其值通過工廠函數(int())設定為0。 3.3 有序字典
有序字典collections.OrderedDict是以資料項目的插入順序進行儲存。
import collectionsd = collections.OrderedDict([('first', 1), ('second', 2), ('third', 3)])print(d.keys())[out]odict_keys(['first', 'second', 'third'])
可以看出我們通過二元組列表建立有序字典後,擷取去鍵視圖也為有序的。
有序字典另一種稍專業一些的用途是產生排序字典。給定一個字典d,可以按如下方式轉換為排序字典:d=collections.OrderedDict(sorted(d.items()))。 4、組合資料類型的迭代與複製 4.1 迭代子、迭代操作與函數
iterable資料類型每次返回其中的一個資料項目。任意包含__iter__() 方法的對象或任意序列(也即包含__getitem__()方法的對象)都是一個iterable,並可以提供一個迭代子。迭代子是一個對象,該對象可以提供__next__()方法,該方法依次返回每個相繼的資料項目,並在沒有資料項目時產生StopIteration異常。
常見的迭代操作符與函數(s與t為序列):
| 文法 |
描述 |
| s+t |
返回一個序列,該序列是s與t的串連 |
| s*n |
返回一個序列,該序列是s的n個副本的串連 |
| x in i |
如果x出現在iterable i中,返回True |
| all(i) |
如果iterable i中的每一項都評估為True,就返回True |
| any(i) |
如果iterable i中的任意項評估為True,就返回True |
| emumerate(i, start) |
通常用於for… in 迴圈中,提供一個(index, item)元組序列,其中索引其實值為0或start |
| len(x) |
返回x的“長度” |
| max(i, key) |
返回iterable i中的最大的項,如果給定的是key函數,就返回key(item)值的最大項 |
| min(i, key) |
返回iterable i中的最小的項,如果給定的是key函數,就返回key(item)值的最小項 |
| range(start, stop, step) |
返回一個整數迭代子,使用一個參數(stop)時,迭代子的取值範圍從0到stop-1;使用兩個參數(start與stop)時,迭代子取值範圍從start到stop-1;使用三個參數時,迭代子取值範圍從start到stop-1,每兩個值之間間隔step |
| reversed(i) |
返回一個迭代子,該迭代子以反序從迭代子i中的返回項 |
| sorted(i, key, reverse) |
以排序後順序從迭代子i返回項,key用於提供DSU(修飾、排序、反修飾)排序,如果reverse為True,則排序以反序進行 |
| sum(i, start) |
返回iterable i中項的和,加上start(預設為0),i可以包含字串 |
| zip(i1, …, iN) |
返回元組的迭代子,使用迭代子i1到iN |
資料項目返回的順序依賴於底層的iterable。對列表和元組等情況,資料項目的傳回值通常從第一個資料項目開始依次返回,而對於字典與集合,迭代子是任意順序的返回項。 4.2 組合類別型的複製
由於資料片總是曲子某個資料項目的一個單獨副本,所以擷取一個列表的副本可以通過下面方式:
lst = ['apple', 'dog'