敲黑板,面向對象的三大特徵:python
封裝、繼承和多態。函數
封裝就是隱藏底層的實現細節,只提供公有的接口供外界訪問, 這樣當底層實現細節改變的時候,就不會對外界形成影響。ui
在類的設計角度,咱們能夠將屬性或方法(類的成員)定義爲私有,來實現封裝。設計
私有成員只能在定義類的內部進行訪問,在類外是沒法進行訪問的。3d
私有成員的定義方式:以_進行開頭,可是不能以兩個或多個進行結尾。code
class Computer: def __init__(self,cpu): self.cpu = cpu # 私有屬性(私有的實例屬性) self.__memory = 1024 # 在定義私有屬性「類的內部」,能夠訪問私有成員 #print(self.__memory) c = Computer("某cpu") c.__memory # 能夠發現私有屬性不可以在外部直接訪問
結果以下:對象
class Computer: def __init__(self,cpu): self.cpu = cpu # 私有屬性(私有的實例屬性) self.__memory = 1024 # 在定義私有屬性「類的內部」,能夠訪問私有成員 print(self.__memory) def x(self): pass # 若是想要採用公有的方法(在類的外部),訪問私有屬性。須要額外定義兩個方法 def set_memory(self,memory): self.__memory = memory def get_memory(self): return self.__memory c = Computer("某cpu") c.get_memory()
結果以下:blog
爲何非要定義爲:私有屬性呢?定義爲通常的實例屬性不是也能夠嗎?繼承
緣由在於:定義爲私有屬性後。當咱們之後須要對類中某屬性作出修改時,只須要在內部修改,而不會對外部的使用者,產生影響。接口
假如不將memory定義爲私有屬性
class Computer: def __init__(self, cpu): self.cpu = cpu self.memory = 1024 c = Computer("某cpu") print(c.memory) # 1024 c.memory = 6666 print(c.memory) # 6666
假如說,因爲某種業務要求,須要將memory改成memory2,那麼,咱們不只須要在內部進行修改。同時外部調用者也須要進行修改。假如你有不少粉絲使用這個,估計都會罵你(假如代碼中有不少行都須要將memory改成memory2)
其實,私有屬性也並不是真正的私有。只是將名稱進行了一下假裝而已。
假裝成了:類名_私有屬性的名稱
這就意味着,在類的外部,咱們能夠經過真實名稱對私有屬性進行訪問。
可是,不建議這麼作。假裝就是爲了保證封裝性,而你非要去捅破。
class Computer: def __init__(self,cpu): self.cpu = cpu self.__memory = 1024 c = Computer("某cpu") c.__memory c._Computer__memory # 切記不要這麼作。這樣作破壞了封裝性
結果以下:
class PythonTeacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"個人名字是{self.name},所在小組是{self.group}") def teach(self): print("打開pycharm") print("輸入代碼") print("知識點講解") class JaVaTeacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"個人名字是{self.name},所在小組是{self.group}") def teach(self): print("打開eslipse") print("輸入代碼") print("知識點講解")
繼承體現的是通常與特殊的關係。若是兩個類A與B,A(蘋果)是一種特殊的B(水果),則咱們就稱A繼承了B,A就是子類,B就是父類。
子類一旦繼承了父類,子類就會成爲一種特殊的父類,子類就會具有父類的一切特徵。所以,父類可以作的事情,子類也能夠作到。
子類繼承了父類,子類就會繼承父類中定義的成員,就好象子類中本身定義了同樣。
class Fruit: def show(self): print("水果") # 繼承,在定義類時,給出繼承的父類 class Apple(Fruit): pass f = Fruit() f.show() a = Apple() a.show()
結果以下:
定義類時,若沒有顯示的繼承任何類,則代表繼承object類,object是python中最根層次的類。
咱們能夠將公共的功能提取出來,放入父類中。而後使用每個子類去繼承父類。這樣,就無需將這些公共的功能分別放在子類中實現。從而避免了代碼的重複性。
子類繼承父類,子類能夠吸取「父類的功能」,此外,子類還能夠增長本身特有的功能。若是父類的功能對於子類來講不適用,子類就能夠改造(重寫)父類中的功能。
class Bird: def fly(self): print("鳥飛") def describe(self): print("有羽毛,無牙齒,蛋生") class Ostrich(Bird): # 父類中的fly功能,不適合鴕鳥。所以,子類須要對父類的功能進行修改 def fly(self): print("不會飛") # 子類增長本身特有的功能 def run(self): print("高速奔跑") c = Ostrich() c.fly(),c.describe(),c.run()
結果以下:
子類能夠繼承父類中定義的:類屬性、實例屬性;類方法、實例方法;靜態方法。
class Father: class_attr = 1 def __init__(self): self.instance_attr = 2 def instance_method(self): pass @classmethod def class_method(cls): pass @staticmethod def static_method(): pass class Son(Father): pass s = Son()
而後子類就能夠調用父類的類屬性、實例屬性;類方法、實例方法;靜態方法。
對於父類中的實例屬性,咱們須要留意。若是子類中定義了本身的init方法,則不會調用父類的init方法。所以,父類方法中綁定的實例屬性,就不會綁定到子類對象上,也就是說父類的實力屬性,子類不會獲得繼承。
class Father: class_attr = 1 def __init__(self): self.instance_attr = 2 def instance_method(self): pass @classmethod def class_method(cls): pass @staticmethod def static_method(): pass class Son(Father): def __init__(self): pass so = Son() so.instance_attr
結果以下:
有時候,父類的初始化,可能"並不徹底適合於"子類。這是,子類須要定義本身的init方法。
"並不徹底適合於"指的是:父類中,有的實例屬性適合雨子類,有的不適合於子類。子類中既要定義本身的init方法,又想使用父類中部分實例屬性,那麼該怎麼作呢?
class Person(): delf __init__(self,name,age): self.name = name self.age = age class Student(Person): delf __init__(self,name,age,id): self.name = name self.age = age self.id = id # 父類的初始化不徹底適合於子類,可是,也沒有徹底不適合於子類
整改:在子類的init方法中,去調用父類的init方法,這樣能夠"避免代碼重複"。
class Person(): def __init__(self,name,age): self.name = name self.age = age class Student(Person): def __init__(self,name,age,id): # 調用父類的__init__方法 super().__init__(name,age) # 調用父類的__init__方法 self.id = id s = Student("梁某人",18,2017011) s.name,s.age,s.id
結果以下:
實際上,私有屬性也是能夠被子類繼承的。只不過,子類繼承的不是私有屬性原本的名字,而是私有屬性假裝後的名字。
雖然子類能夠繼承並訪問父類的私有屬性,可是不建議這麼作。既然是私有的,確定是不肯意咱們去訪問的。
class Father: def __m(self): print("私有方法") class Son(Father): def p(self): # 經過假裝以後的名字,進行訪問 self._Father__m() s = Son() s.p()
結果以下:
① isinstance(參數一,參數二)
class Father: pass class Son(Father): pass f = Father() s = Son()
來檢測一下:
② issubclass()
class Father: pass class Son(Father): pass f = Father() s = Son()
再來檢測一下:
當父類中的成員,對子類不徹底適用時,子類就能夠從新定義該成員。
class Bird: def fly(self): print("鳥飛") class Ostrich(Bird): # 父類中的fly功能,不適合鴕鳥。所以,子類須要對父類的功能進行修改 def fly(self): print("不會飛") # 子類增長本身特有的功能 def run(self): print("高速奔跑") o = Ostrich() o.fly()
結果以下:
class Bird: def fly(self): print("鳥飛") class Ostrich(Bird): # 父類中的fly功能,不適合鴕鳥。所以,子類須要對父類的功能進行修改 def fly(self): # 經過super()方法,能夠實現對父類中同名方法的訪問 super().fly() # super()既能夠調用父類中的私有屬性。也能夠調用父類中的方法 print("不會飛") o = Ostrich() o.fly()
結果以下:
python中,一個子類能夠繼承多個父類。多個父類的成員,均可以被子類所繼承。繼承多個父類使用 , 分割。
class Rectangle: def area(self): print("矩形求面積") class Diamond: def area(self): print("菱形求面積") class Square(Rectangle,Diamond): #老是按照這裏的前後順序,一一繼承 def t(self): self.area() s = Square() s.t()
結果以下:
class Rectangle: def area(self): print("矩形求面積") class Diamond: def area(self): print("菱形求面積") class Square(Diamond,Rectangle): #老是按照這裏的前後順序,一一繼承 def t(self): self.area() s = Square() s.t()
結果以下:
多繼承:按照繼承原則,每一個父類看做一個分支。按照順序進行查找,深度優先。可是有一個原則:子類必定會在父類以前被搜索。
class Teacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"個人名字是{self.name},所在小組是{self.group}") def teach(self): print("輸入代碼") print("知識點講解") class PythonTeacher(Teacher): def __init__(self,name,group): super().__init__(name,group) def teach(self): print("打開pycharm") super().teach() class JaVaTeacher(Teacher): def __init__(self,name,group): super().__init__(name,group) def teach(self): print("打開eslipse") super().teach() p = PythonTeacher("梁某人", 10) print(p.introcude(), p.teach())
結果以下:
j = JaVaTeacher("梁三",666) print(j.group,j.teach())
結果以下:
這個在python中基本體現不出來,知道面向對象有多態這個特性就好了。