前言:
本文代碼基於python3
Content:
1.python中的序列類分類
2. python序列中abc基類繼承關系
3. 由list的extend等方法來看序列類的一些特定方法
4. list這種序列類的一大特點:切片。和如何實現可切片對象。到如何自定義一個序列類。
5. biset維護排序序列
6. 什么時候使用list
7.列表推導式、生成器表達式、字典推導式
1.python中的序列類分類
a.什么是python的序列類?
之前提到的魔法函數這種時候就很重要啦。滿足序列類相關的協議就稱為python里的序列類。python內置的序列類有dict、tuple、list等。
而我們自定義序列類的話,由於魔法函數的存在。序列的相關魔法方法允許我們自己創建的類擁有序列的特性,讓其使用起來就像 python 的內置序列。
b.python按分類來看有哪些序列類?
- 容器序列:list,tuple,deque(可以放任意的類型的容器)
- 扁平序列:str,bytes,bytearray,array.array(可以使用 for循環遍歷的)
- 可變序列:list,deque,bytearray,array
- 不可變:str,tuple,bytes
Python標准庫提供了大量使用C來實現的序列類型,
從序列中的元素類型是否一致作為標准,包括容器序列(Container sequences,包括list、tuple、collections.deque等)和固定序列(Flat sequences,包括str、bytes、bytearray、memoryview、array.array)等。
ps.容器序列中實際存放的元素是對其他任意對象的引用,而固定序列中存放是真正的是元素值,因此所有的元素必須是相同類型,並且只能是Python基本類型(字符、字節、數字等)的數據。
如果從序列中的元素是否能夠被修改的標准來看,Python的序列類型又分為可變序列(Mutable sequences,包括list、bytearray、array.array、collections.deque、memoryview等)和不可變序列(Immutable sequences,包括tuple、str、bytes等)
c.序列常見操作
索引(index)
分片(slicing)
序列相加(拼接)
乘法(重復)
成員資格(in)
長度(len)
max()
min()
可以迭代
sorted
enumerate
zip
filter
map
2. python序列中的abc繼承關系
在python的collection模塊中,有abc模塊,和容器相關的抽象基類和數據結構都在其中。
那么abc模塊中,具體有哪些類呢?
其中,Sequence就是不可變序列的方法集合的抽象基類,MutableSequence是集合了可變序列的方法和協議的抽象基類。
這些抽象類之間的關系:
a.可變序列(MutableSequence)從不可變序列(Sequence)那里繼承了一些方法.
b.Sequence繼承了collection,collection又繼承了Sized、Container、Iterable
c.python的內置序類型並沒有直接繼承這些基類,但是這些基類定義了某種特性序列的方法和協議,了解這些基類間的繼承關系能很好的幫助我們了解python的內置序列類型。
綜上可得圖:
3. 由list的extend等方法來看序列類的一些特定方法調用
對list序列進行添加操作一般有幾種方法?
+、+=、extend、append
這里有幾個好玩的地方:
a.+和+=的區別
可以看到+=的對象可以是tuple,而+不可以。
實際上+=是調用了一個魔法函數 __iadd__實現的。使用+=的時候,實際上還是調用了extend方法。
extend傳遞的參數類型是可迭代類型,用for循環,它會遍歷可迭代的類型,一個個加到列表里。
b.extend、append的區別
上面已經貼出了extend的實現,現在看append的實現:
很明顯的一點,一個直接用insert把對象插入,一個遍歷對象加入。
4. list這種序列類的一大特點:切片。和如何實現可切片對象。到如何自定義一個序列類。
a.python的切片的一些用法:
alist = [3,4,5,6,7,9,11,13,15,17] print(alist[::]) # 返回包含原列表中所有元素的新列表 print(alist[::-1]) # 返回原列表的逆序排列 print(alist[::2]) # 返回原列表的偶數位數據 print(alist[1::2]) # 獲取奇數位置的數據 print(alist[3:6]) # 指定切片的開始和結束位置 print(alist[0:100]) # 切片位置大於列表長度時,從列表尾部截斷 print(alist[100:]) # 切片開始位置大於列表長度時,返回空列表 alist[len(alist):]=[9] # 在列表尾部增加元素 print(alist) alist[:0] = [1,2] # 前面的0省略了,相當於是alist[0:0] = [1,2] print(alist) # 在列表的頭部增加元素 alist[3:3] =[4] # 在列表中間插入元素 print(alist) alist[:3] = [1,2] # 相當於是alist[0:3] = [1,2] 替換列表元素 alist[3:] = [4,5,6] # 替換元素,結果按照兩邊的最短元素來決定. print(alist) alist[:3] = [] # 刪除列表中前三個元素 del alist[:3] # 切片元素連續 del alist[::2] # 隔一個刪除一個,切片元素不連續
b.自己實現一個可切片的序列類(包括可切片、可添加等內置序列類型有的操作)
自定義序列的相關魔法方法允許我們自己創建的類擁有序列的特性,讓其使用起來就像 python 的內置序列(dict,tuple,list,string等)。
如果要實現這個功能,就要遵循 python 的相關的協議。所謂的協議就是一些約定內容。例如,如果要將一個類要實現迭代,可以實現__iter__()
或者 __getitem__()其中一個方法
。
例子:自定義一個可以被切片的Group類:
import numbers class Group: # 支持切片操作 def __init__(self, group_name, company_name, staffs): self.group_name = group_name self.company_name = company_name self.staffs = staffs def __reversed__(self): self.staffs.reverse() # 因為object[] 和 object[::]都會調動這個方法 def __getitem__(self, item): # 取到class cls = type(self) #判斷傳遞進來的是slice類型還是int類型,返回不同的類型和操作, if isinstance(item, slice): return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item]) if isinstance(item, numbers.Integral): return self.staffs[item] def __iter__(self): return iter(self.staffs) def __len__(self): return len(self.staffs) def __str__(self): return '組員有:{}'.format(self.staffs) def __contains__(self, item): if item in self.staffs: return True else: return False staffs = ['tangrong1', '123', '456', '789'] group = Group('A', 'TR', staffs=staffs) sub_group = group[:2] print(group) print(sub_group) if 'A' in group: # 這里會調用__contains__魔法函數 print('yes') for item in group: print(item) reversed(group) # 實際上是調用了__reversed__魔法函數 print(group)
輸出正常。
一些相關的魔法函數:
-
__len__(self) 返回容器的長度。可變和不可變容器都要實現它,這是協議的一部分。
- __getitem__(self, key) 定義當某一項被訪問時,使用self[key]所產生的行為。這也是可變容器和不可變容器協議的一部分。如果鍵的類型錯誤將產生TypeError;如果key沒有合適的值則產生KeyError。
- __setitem__(self, key, value) 定義當一個條目被賦值時,使用self[key] = value所產生的行為。這也是可變容器協議的一部分。而且,在相應的情形下也會產生KeyError和TypeError。
-
__delitem__(self, key) 定義當某一項被刪除時所產生的行為。(例如del self[key])。這是可變容器協議的一部分。當你使用一個無效的鍵時必須拋出適當的異常。
- __iter__(self) 返回一個迭代器,尤其是當內置的iter()方法被調用的時候,以及當使用for x in container:方式進行循環的時候。 迭代器要求實現next方法(python3.x中改為__next__),並且每次調用這個next方法的時候都能獲得下一個元素,元素用盡時觸發 StopIteration 異常。 而其實 for 循環的本質就是先調用對象的__iter__方法,再不斷重復調用__iter__方法返回的對象的 next 方法,觸發 StopIteration 異常時停止,並內部處理了這個異常,所以我們看不到異常的拋出。 這種關系就好像接口一樣。
ps:
可迭代對象:對象實現了一個__iter__方法,這個方法負責返回一個迭代器。
迭代器:內部實現了next(python3.x為__next__)方法,真正負責迭代的實現。當迭代器內的元素用盡之后,任何的進一步調用都之后觸發 StopIteration 異常,所以迭代器需要一個__iter__方法來返回自身。
所以大多數的迭代器本身就是可迭代對象。這使兩者的差距進一步減少。
但是兩者還是不同的,如果一個函數要求一個可迭代對象(iterable),而你傳的迭代器(iterator)並沒有實現__iter__方法,那么可能會出現錯誤。
不過一般會在一個類里同時實現這兩種方法(即是可迭代對象又是迭代器),此時__iter__方法只要返回self就足夠的了。當然也可以返回其它迭代器。
- __reversed__(self) 實現當reversed()被調用時的行為。應該返回序列反轉后的版本。僅當序列是有序的時候實現它,例如列表或者元組。
- __contains__(self, item) 定義了調用in和not in來測試成員是否存在的時候所產生的行為。這個不是協議要求的內容,但是你可以根據自己的要求實現它。當__contains__沒有被定義的時候,Python會迭代這個序列,並且當找到需要的值時會返回True。
- __missing__(self, key) 其在dict的子類中被使用。它定義了當一個不存在字典中的鍵被訪問時所產生的行為。(例如,如果我有一個字典d,當"george"不是字典中的key時,使用了d["george"],此時d.__missing__("george")將會被調用)。
5. biset維護排序序列
a.biset模塊干嘛的。模塊里的insort干嘛的

6. 什么時候不應該使用list而用array
list和array的區別:
list是一個容器,裝任何類型的數據。而array只能裝指定類型的數據。

例子:用布隆過濾器的時候 就用了array。這時候array性能高list很多
7.列表推導式、生成器表達式、字典推導式
# 列表推導式 # 1.提取出1-20之間的奇數 odd_list = [] for i in range(21): if i % 2 == 1: odd_list.append(i) print(odd_list) # 使用列表推導式 odd_list = [x for x in range(21) if x % 2 == 1] print(odd_list) # 列表推導式的格式 # [on True for x in iteralbe 條件表達式(過濾)] # 邏輯復雜的情況 def handle_item(item): return item * item odd_list = [handle_item(x) for x in range(21) if x % 2 == 1] print(odd_list) # 列表表達式的前面可以是一個函數,也可以是一個函數,但是不能是匿名函數 # 生成器表達式,將列表推導式的[]改成(),就變成了生成器表達式 gen = (x for x in range(21) if x % 2 == 1) print(gen) # <generator object <genexpr> at 0x000001CF1B01C8E0> print(type(gen)) # <class 'generator'> for item in gen: print(item) # 字典推導式,顛倒key和value my_dict = {'bob1': 22, 'bob3': 23, 'bob4': 5} reversed_dict = {value: key for key, value in my_dict.items()} print(reversed_dict) # 集合推導式 set # 如何將一個字典的key全部放到一個集合當中. my_set = {key for key in my_dict.keys()} # 也可以使用 my_set = set(my_dict.keys()) print(type(my_set)) print(my_set)