Python第八周 學習筆記(1)
- 2020 年 1 月 8 日
- 筆記
繼承
- 基本概念個體繼承自父母,繼承了父母的一部分特徵,但也可以有自己的個性
- 子類繼承了父類,就直接擁有了父類的屬性和方法,也可以定義自己的屬性、方法,甚至對父類的屬性、方法進行重寫
Python繼承實現
- class Cat(Animal) 括弧中為該類的父類列表
- 如果類定義時沒有父類列表,則只繼承object類
- object類是所有類的祖先類
類的特殊屬性與方法
base
類的基類
bases
類的基類的元組
mro
方法解析時的類的查找順序,返回元組
- mro()
- 作用同上,返回列表
- subclasses()
- 返回類的子類的列表
Python繼承中的注意事項
- 屬於父類的私有成員,子類即使與父類存在繼承關係也不可直接訪問(可通過改名後的屬性名訪問,但慎用)
- 例子:
class Animal: __count=100 heigtht=0 def showcount3(self): print(self.__count) class Cat(Animal): name='cat' __count=200 c=Cat() c.showcount3()
結果為100
因為子類調用了父類獲取父類私有變數的方法 self.count的count作用域是在父類下的,其真正調用的self._Animal__count,而這個屬性只有父類有
- 解決的辦法:自己私有的屬性,用自己的方法讀取和修改,不要藉助其他類的方法,即使是父類或派生類的方法
屬性查找順序
- 實例dict -> 類dict -> 父類dict
多繼承
- 一個類繼承自多個類就是多繼承,他將具有多個類的特徵
- 多繼承容易引起二義性,為此Python3利用C3演算法生成MRO有序列表解決多繼承的二義性(拓撲排序)
Mixin
- 本質是多繼承
- 體現的是一種組合的設計模式
Mixin類使用原則
- 類中不應該顯示的出現init初始化方法
- 通常不能獨立工作,因為它是準備混入別的類中的部分功能實現 其祖先類也應是Mixin類
- 使用Mixin時,其通常在繼承列表的第一個位置
- 裝飾器實現
def printable(cls): def _print(self): print(self.content, 'decorator') cls.print = _print return cls class Document: def __init__(self, content): self.content = content class Word(Document): pass class Pdf(Document): pass @printable class PrintableWord(Word): pass print(PrintableWord.__dict__) print(PrintableWord.mro()) pw = PrintableWord('test string') pw.print() @printable class PrintablePdf(Word): pass
- 優點: 簡單方便,在需要的地方動態增加,直接使用裝飾器
Mixin實現
class Document: def __init__(self, content): self.content = content class Word(Document): pass class Pdf(Document): pass class PrintableMixin: def print(self): print(self.content, 'Mixin') class PrintableWord(PrintableMixin, Word): pass print(PrintableWord.__dict__) print(PrintableWord.mro()) pw = PrintableWord('test string') pw.print() class SuperPrintableMixin(PrintableMixin): def print(self): print('~' * 20) super().print() print('~' * 20) class SuperPrintablePdf(SuperPrintableMixin, Pdf): pass print(SuperPrintablePdf.__dict__) print(SuperPrintablePdf.mro()) spp = SuperPrintablePdf('super print pdf') spp.print()
Mixin類和裝飾器
- 這兩種方式都可以使用,看個人喜好
- 如果還需要繼承就得使用Mixin類
二分法
- 序列必須有序
- 時間複雜度O(logn)
lst = [37, 99, 73, 48, 47, 40, 40, 25, 99, 51] lst.sort() def bi_insert(lst, value): high = len(lst) low = 0 while low < high: mid = (low + high) // 2 if value > lst[mid]: low = mid + 1 else: high = mid - 1 lst.insert(low, value) bi_insert(lst, 100) bi_insert(lst, 40) print(lst)
bisect模組
bisect.bisect_left(a, x, lo=0, hi=len(a)) 查找在有序列表a中插入x的index,lo和hi用於指定列表的區間,默認是整個列表
如果x已經存在,在其左邊插入,返回值為index
bisect.bisect_right(a, x, lo=0, hi=len(a))
與bisect_right類似,如果x已經存在,在其右邊插入
bisect.insort_left(a, x, lo=0, hi=len(a))
在有序列表a中插入x
bisect.insort_right(a, x, lo=0, hi=len(a))
和insort_left函數類似,如果x已經存在,在其右邊插入
習題
- 判斷學生成績,成績等級A-E,90分以上為A,80-89為B,70-79為C,60-69為D,60以下為E
import bisect def get_grade(score): breakpoints = [60, 70, 80, 90] grades = 'EDCBA' return grade[bisect.bisect(breakpoints, score)] for x in (50,60,69,79,85,100): print('{} -> {}'.format(x,get_grade(x)))
魔術方法
dir
返回類或者對象的所有成員名稱列表。
dir()就是調用dir()
如果提供dir(),則返回屬性列表,否則會盡量從dict屬性中收集資訊
dir()對於不同類型的對象具有不同的行為:
如果對象是模組對象,返回的列表包含模組的屬性名
如果對象是類型或者類對象,返回的列表包含類的屬性名,及它的基類屬性名
否則,返回列表包含對象的屬性名、它的類的屬性名和類的基類的屬性名
魔術方法分類
1.創建、初始化與銷毀
- init與del
2.hash
- 內建函數hash()調用的返回值,返回一個整數。
- 如果定義這個方法,則該類的實例可hash
eq
- 對應==,判斷兩個對象是否相等,返回bool類型
- 對象去重時
- 先判斷hash值,如果hash值相等(hash衝突),再調用eq方法判斷
- 去重一定需要t提供eq方法
- list、bytesarray,dict等不可hash的實例是因為他們的類的封裝里有 hash = None
習題
- 設計二維坐標類Point,使其成為可hash類型,並比較兩個坐標實例是否相等
3.bool
- 內建函數bool(),或者對象放在邏輯表達式的位置,返回bool類型
- 如果沒有定義bool(),就找len()返回長度,非0為True。
- 如果len()也沒有定義,那麼所有實例都返回True
4.可視化
repr
- 內建函數repr()對一個對象獲取字元串表達
- 返回字元串
- 如果沒有定義,就直接返回object的repr()
str
- str()、format()、print()調用,返回字元串
- 如果沒有定義,就調用repr方法,如果__repr_沒有定義,直接返回對象記憶體地址資訊
bytes
- bytes()調用,返回bytes類型
5.運算符重載
<,<=,==,>,>=,!= lt,le,eq,gt,ge,ne
+,-,*,/,%,//,**,divmod add,sub,mul,truediv,mod,floordiv,pow,divmod
+=,-=,*=,/=,%=,//=,**=
iadd,isub,imul,itruediv,imod,ifloordiv,ipow
一般只實現eq;lt,gt實現其一,le,ge實現其一 即可
習題 完成Point類,實現判斷點相等,並完成向量加法
6.容器和大小
len
len()會調用此方法
bool()調用時,如果沒有bool方法,則調用len,返回非0為True
iter
迭代時調用,返回迭代器對象
contains
in 調用,如果沒實現,就調用iter遍歷
getitem
實現self[key]
setitem
與getitem類似
missing
dict類調用getitem時 key不存在,調用此方法
習題 改造購物車類成方便操作的容器類
7.可調用對象
call
在類中定義此方法後,實例可調用
習題 實現斐波那契類,對象可調用
class Fibonacci: def __init__(self): self.lst = [0, 1, 1] def __call__(self, index): if index < 0: raise Exception() self.generator(index) return self[index] def __len__(self): return len(self.lst) def __iter__(self): # yield from self.lst return iter(self.lst) def __getitem__(self, item): return self.lst[item] def generator(self, index): for i in range(len(self), index + 1): self.lst.append(self[i - 1] + self[i - 2])
8.上下文管理
- with … as語法
- 實現enter和exit方法,就屬於上下文管理對象 enter
- 如果存在該方法,with語法會把該方法的返回值作為綁定到as子句中指定的變數上
exit(self, exc_type, exc_value, traceback)
- 退出上下文時調用
- exc_type 異常類型
- exc_value 異常描述
- traceback 異常追蹤資訊
- exit返回值為等效True的值,則壓制異常
- 應用場景:
- 增強功能
- 資源管理
- 許可權驗證
contextlib.contextmanager
裝飾器
習題 為函數執行計時
9.反射
運行時,區別於編譯時,指程式被載入到記憶體中執行的時候
運行時獲取類型資訊