1. 程式人生 > >面向物件三大特性:封裝、繼承、多型

面向物件三大特性:封裝、繼承、多型

封裝:

  1. 將屬性和方法放到一起做為一個整體,然後通過例項化物件來處理;
  2. 隱藏內部實現細節,只需要和物件及其屬性和方法互動就可以了;
  3. 對類的屬性和方法增加 訪問許可權控制。

私有許可權:在屬性名和方法名 前面 加上兩個下劃線 __

  1. 類的私有屬性 和 私有方法,都不能通過物件直接訪問,但是可以在本類內部訪問;
  2. 類的私有屬性 和 私有方法,都不會被子類繼承,子類也無法訪問;
  3. 私有屬性 和 私有方法 往往用來處理類的內部事情,不通過物件處理,起到安全作用。

class Master(object):
    def __init__(self):
        self.kongfu = "古法煎餅果子配方" 
    def make_cake(self):          
        print("[古法] 按照 <%s> 製作了一份煎餅果子..." % self.kongfu)

class School(object):
    def __init__(self):
        self.kongfu = "現代煎餅果子配方"

    def make_cake(self):
        print("[現代] 按照 <%s> 製作了一份煎餅果子..." % self.kongfu)

class Prentice(School, Master):
    def __init__(self):
        self.kongfu = "貓氏煎餅果子配方"
        # 私有屬性,可以在類內部通過self呼叫,但不能通過物件訪問
        self.__money = 10000  

    # 私有方法,可以在類內部通過self呼叫,但不能通過物件訪問
    def __print_info(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        self.__init__()
        print("[貓氏] 按照 <%s> 製作了一份煎餅果子..." % self.kongfu)

    def make_old_cake(self):
        Master.__init__(self) 
        Master.make_cake(self)


    def make_new_cake(self):
        School.__init__(self) 
        School.make_cake(self)

class PrenticePrentice(Prentice):
    pass


damao = Prentice()
# 物件不能訪問私有許可權的屬性和方法
# print(damao.__money)
# damao.__print_info()


pp = PrenticePrentice()
# 子類不能繼承父類私有許可權的屬性和方法
print(pp.__money) 
pp.__print_info()

總結

  • Python中沒有像C++中 public 和 private 這些關鍵字來區別公有屬性和私有屬性。
  • Python是以屬性命名方式來區分,如果在屬性和方法名前面加了2個下劃線'__',則表明該屬性和方法是私有許可權,否則為公有許可權。

多型

所謂多型:定義時的型別和執行時的型別不一樣,此時就成為多型 ,多型的概念是應用於Java和C#這一類強型別語言中,而Python崇尚“鴨子型別”。

鴨子型別:雖然我想要一隻"鴨子",但是你給了我一隻鳥。 但是隻要這隻鳥走路像鴨子,叫起來像鴨子,游泳也像鴨子,我就認為這是鴨子。

Python的多型,就是弱化型別,重點在於物件引數是否有指定的屬性和方法,如果有就認定合適,而不關心物件的型別是否正確。

  • Python虛擬碼實現Java或C#的多型

class F1(object):
    def show(self):
        print('F1.show')

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

# 由於在Java或C#中定義函式引數時,必須指定引數的型別
# 為了讓Func函式既可以執行S1物件的show方法,又可以執行S2物件的show方法,
# 所以在def Func的形參中obj的型別是 S1和S2的父類即F1
# 
# 而實際傳入的引數是:S1物件和S2物件

def Func(F1 obj): 
    """Func函式需要接收一個F1型別或者F1子類的型別"""

    print(obj.show())

s1_obj = S1()
Func(s1_obj) # 在Func函式中傳入S1類的物件 s1_obj,執行 S1 的show方法,結果:S1.show

s2_obj = S2()
Func(s2_obj) # 在Func函式中傳入Ss類的物件 ss_obj,執行 Ss 的show方法,結果:S2.show

通俗點理解:定義obj這個變數是說的型別是:F1的型別,但是在真正呼叫Func函式時給其傳遞的不一定是F1類的例項物件,有可能是其子類的例項物件, 這種情況就是所謂的多型

  • Python “鴨子型別”
class F1(object):
    def show(self):
        print('F1.show')

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

def Func(obj):  
    # python是弱型別,即無論傳遞過來的是什麼,obj變數都能夠指向它,這也就沒有所謂的多型了(弱化了這個概念)
    print(obj.show())

s1_obj = S1()
Func(s1_obj) 

s2_obj = S2()
Func(s2_obj)

繼承

  • 在程式中,繼承描述的是多個類之間的所屬關係。
  • 如果一個類A裡面的屬性和方法可以複用,則可以通過繼承的方式,傳遞到類B裡。
  • 那麼類A就是基類,也叫做父類;類B就是派生類,也叫做子類。
# 父類
class A(object):
    def __init__(self):
        self.num = 10

    def print_num(self):
        print(self.num + 10)
# 子類
class B(A):
    pass


b = B()
print(b.num) 
b.print_num()

---單繼承:子類只繼承一個父類

說明:

  • 雖然子類沒有定義__init__方法初始化屬性,也沒有定義例項方法,但是父類有。所以只要建立子類的物件,就預設執行了那個繼承過來的__init__方法

總結:

  • 子類在繼承的時候,在定義類時,小括號()中為父類的名字
  • 父類的屬性、方法,會被繼承給子類

---多繼承:子類繼承多個父類

說明:

  • 多繼承可以繼承多個父類,也繼承了所有父類的屬性和方法
  • 注意:如果多個父類中有同名的 屬性和方法,則預設使用第一個父類的屬性和方法(根據類的魔法屬性mro的順序來查詢)
  • 多個父類中,不重名的屬性和方法,不會有任何影響。