Python基礎(二十二):面向對象「類」第五課——封裝、繼承、多態

敲黑板,面向對象的三大特徵: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方法,這樣能夠"避免代碼重複"。

super()方法登場

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中基本體現不出來,知道面向對象有多態這個特性就好了。

相關文章
相關標籤/搜索