oop思想
任意一個任務,首先想到的是任務的構成和實現過程。html
類和對象的概念python
類的內容設計模式
類的命名函數
訪問類和對象的成員oop
# 對象成員檢查 obj.__dict__ # 類成員檢查 class_name.__dict__
實例設計
# 定義一個簡單的類 class StudentPython(): name = None age = 18 def Studentplay(self): print("learning python") # David爲對象,此時實例化類 David = StudentPython() print(David.name) print(David.age) David.Studentplay()
類和對象均可以儲存成員,成員能夠歸類全部也能夠歸對象全部。code
建立對象時,類中的成員不會放入對象中,而是獲得一個空對象。orm
經過對象對類中成員從新賦值或者經過對象添加成員時,對應成員會保存在對象中,而不會修改類成員。htm
實例對象
class Teacher(): name = "aaa" age = 28 def TeacherSay(self): self.name = "Mary" self.age = 20 print("My name is {0}".format(self.name)) print("My age is {0}".format(self.age)) t = Teacher() print(t.name) print(t.age) t.TeacherSay() ''' aaa 28 My name is Mary My age is 20 '''
self在對象的方法中表示當前對象自己,若是經過對象調用方法,那麼該對象會自動傳入到當前方法的第一個參數中。
self並非關鍵字,理論上能夠用任何一個普通變量名代替。
方法中有self形參的稱爲非綁定類的方法,能夠經過對象訪問,沒有self的稱爲綁定類方法,只能經過類訪問。
實例
class Teacher(): name = "aaa" age = 28 def TeacherSay(self): self.name = "Mary" self.age = 20 print("My name is {0}".format(self.name)) print("My age is {0}".format(self.age)) def TeacherSayAgain(): print(__class__.name) print(__class__.age) print("learning python") t = Teacher() t.TeacherSay() # 調用綁定類方法經過類訪問 Teacher.TeacherSayAgain() ''' My name is Mary My age is 20 aaa 28 learning python '''
三個級別:公開(public),受保護(protected),私有(private)。
判別對象的位置:對象內部,對象外部,子類中。
私有:私有成員是最高級別的封裝,只能在當前類或對象中訪問,外部不能訪問。python的私有不是真私有,是一種爲name mangling的更名策略。
class Person(): # name爲共有成員 name = "David" #__age爲私有成員 __age = 18
受保護:將對象成員進行必定級別的封裝,在父類和子類中能夠訪問,外部不能訪問。
公開:對對象成員沒有任何操做,任何地方均可以訪問。
繼承就是一個類能夠得到另一個類中的成員屬性和方法。
被繼承的爲父類(基類或超類),用於繼承的類爲子類(派生類)。
全部的類都繼承自object類,即全部的類都是object類的子類。
子類繼承父類後並無將父類成員徹底賦值到子類,而是經過引用關係訪問調用。
子類一旦繼承父類,可使用父類中除私有成員外的全部成員屬性和方法,子類還能夠定義獨有的成員屬性和方法。
子類中定義的成員若是和父類成員相同,則優先使用子類成員。
若是想在子類中擴充父類方法,能夠在定義新方法時訪問父類成員來進行代碼重用,能夠父類名.父類方法
也能夠super().父類方法
的格式調用。
super不是關鍵字,而是一個類。super的做用是獲取MRO(MethodResolutionOrder)列表中的第一個類
class Person(): name = "None" __age = 18 _score = 0 def Study(self): print("learning python") class Student(Person): def HaveTest(self): print("have to take exam") # 擴充父類函數,方法一二 def Study(self): Person.Study(self)# 注意這裏有self self.HaveTest() ''' super().Study()# 注意這裏沒有self # super(Student, self).Study()也能夠 self.HaveTest() ''' David = Student() print(David.name) David.Study() ''' None learning python have to take exam '''
繼承中的查找順序:子類優先查找本身的變量,沒有則查找父類變量;
子類中若是構造函數沒有定義,則按照MRO順序查找調用父類的構造函數,子類有定義則不繼續向上查找。
構造函數:每次實例化第一個被自動調用的函數
單繼承和多繼承:單繼承每一個類只能繼承一個類,多繼承每一個類能繼承多個類;單繼承邏輯清晰語法簡單但功能不能受限,多繼承擴展方便但關係混亂且會出現菱形繼承(鑽石繼承)問題。
MRO:是在多繼承中用於保存繼承順序的一個列表;
MRO計算原則:子類永遠在父類前;若是多個父類則根據括號內類的書寫順序存放;若是多個類繼承了同一個父類,孫子類中只會選取括號內第一個父類的父類。
多態就是同一個對象在不一樣狀況下有不一樣狀態出現。
Mixin設計模式:主要採用多繼承方式對類功能進行擴展。首先必須表示某一單一功能,若是有多個功能則寫多個Mixin,當子類沒有繼承某一Mixin類也能照常工做。
class Person(): def __init__(self, name, age): self.name = name self.age = age def Play(self): print("have fun") def Sleep(self): print("sleeping...") # 建立一個Mixin class TeacherMixin(): def Work(self): print("teaching somebody") class StudentMixin(): def Study(self): print("learning python") class Student(Person, StudentMixin): pass class Teacher(Person): def __init__(self): self.name = "Alex" David = Student("David", 18) print("my name is {0}, my age is {1}".format(David.name, David.age)) David.Study() David.Play() print("*" * 20) Alex = Teacher() print("my name is {0}".format(Alex.name)) Alex.Sleep() ''' my name is David, my age is 18 learning python have fun ******************** my name is Alex sleeping... '''
類的成員描述符是爲了在類中對類的成員屬性進行相關操做
三種方式:使用類實現描述器;使用屬性修飾符;使用property函數property(fget, fset, fdel, doc)
class Person(): ''' property函數實例 定義一個Person類,具備name,age屬性, 對於任意輸入的name都但願以大寫字母保存 ''' def fget(self): # 返回操做後的屬性 return self._name def fset(self, name): # 傳入須要操做的屬性 self._name = name.upper() def fdel(self): self._name = "NoName" name = property(fget, fset, fdel, "None") age = 18 David = Person() David.name = "David" print("my name is {0}".format(David.name)) ''' my name is DAVID '''
__dict__
:以字典的方式顯示類成員的組成
__doc__
:獲取類的文檔信息
__name__
:獲取類的名稱,若是在模塊中使用則獲取模塊名稱
__bases__
:以元組方式顯示類的全部父類
魔術方法就是不須要認爲調用,在特定的狀況下自動觸發的方法,統一特徵是方法名被先後兩個下劃線包裹。
__init__
:構造函數
__new__
:對象實例化方法
__call__
:對象當函數時使用
__str__
:對象被看成字符串時使用
__repr__
:返回字符串
__getattr__
:訪問一個不存在的屬性時觸發,此時不會報錯
__gt__
:進行大於判斷的時候觸發
__setattr__
:對成員屬性設置的時候觸發
# __setattr__示例 class A(): def __setattr__(self, name, value): print("設置屬性{0}爲{1}".format(name, value)) ''' 這樣會致使死循環 self.name = value ''' # 爲了不這種狀況,使用父類魔法函數 super().__setattr__(name, value) a = A() a.age = 18
實例方法:必需要建立實例對象才能調用,第一個參數必須是實例對象,該參數名通常約定爲self,若是方法裏面有初始化函數也必須對初始化函數進行傳參。且只能由實例對象調用
類方法:使用裝飾器@classmethod,第一個參數必須是當前類對象,該參數名通常約定爲cls,能夠由實例對象和類對象調用。
靜態方法:使用裝飾器@staticmethod,沒有self和cls參數,能夠由實例對象和類對象調用。
參考博客Python 實例方法、類方法、靜態方法的區別與做用
class Person(): def Work(self): print("have to work") @classmethod def Study(cls): print("have to study") @staticmethod def Sleep(): print("sleeping...") # 實例方法 p = Person() p.Work() #Person.Work()會報錯 # 類方法 p.Study() Person.Study() # 靜態方法 p.Sleep() Person.Sleep()