1. 程式人生 > 其它 >Python 面向物件 繼承

Python 面向物件 繼承

繼承

01. 單繼承

1.1 繼承的概念、語法和特點
1) 繼承的語法
子類 繼承自 父類,可以直接 享受 父類中已經封裝好的方法,不需要再次開發
子類 中應該根據 職責,封裝 子類特有的 屬性和方法

2) 專業術語
Dog 類是 Animal 類的子類,Animal 類是 Dog 類的父類,Dog 類從 Animal 類繼承
Dog 類是 Animal 類的派生類,Animal 類是 Dog 類的基類,Dog 類從 Animal 類派生

3) 繼承的傳遞性
C 類從 B 類繼承,B 類又從 A 類繼承
那麼 C 類就具有 B 類和 A 類的所有屬性和方法
子類 擁有 父類 以及 父類的父類 中封裝的所有 屬性 和 方法

class Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")

# 建立一個物件 - 狗物件
wangcai = Dog()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()
class Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        
print("我會飛") # 建立一個哮天犬的物件 xtq = XiaoTianQuan() xtq.fly() xtq.bark() xtq.eat()
class Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("我會飛")


class Cat(Animal):

    def catch(self):
        print("抓老鼠")

# 建立一個哮天犬的物件
xtq = XiaoTianQuan()

xtq.fly()
xtq.bark()
xtq.eat()

xtq.catch() # 報錯


1.2 方法的重寫
**子類 擁有 父類 的所有 方法 和 屬性
**子類 繼承自 父類,可以直接 享受 父類中已經封裝好的方法,不需要再次開發

當 父類 的方法實現不能滿足子類需求時,可以對方法進行 重寫(override)
重寫 父類方法有兩種情況:
覆蓋 父類的方法
對父類方法進行 擴充套件

1) 覆蓋父類的方法
如果在開發中,父類的方法實現 和 子類的方法實現,完全不同
就可以使用 覆蓋 的方式,在子類中 重新編寫 父類的方法實現
具體的實現方式,就相當於在 子類中 定義了一個 和父類同名的方法並且實現
重寫之後,在執行時,只會呼叫 子類中重寫的方法,而不再會呼叫 父類封裝的方法

class Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("我會飛")

    def bark(self):
        print("叫得跟神一樣...")


xtq = XiaoTianQuan()

# 如果子類中,重寫了父類的方法
# 在使用子類物件呼叫方法時,會呼叫子類中重寫的方法
xtq.bark()


2) 對父類方法進行 擴充套件
如果在開發中,子類的方法實現 中 包含 父類的方法實現
父類原本封裝的方法實現 是 子類方法的一部分
就可以使用 擴充套件 的方式
a.在子類中 重寫 父類的方法
b.在需要的位置使用 super().父類方法 來呼叫父類方法的執行
c.程式碼其他的位置針對子類的需求,編寫 子類特有的程式碼實現
**********
關於 super
在 Python 中 super 是一個 特殊的類
super() 就是使用 super 類創建出來的物件
最常 使用的場景就是在 重寫父類方法時,呼叫 在父類中封裝的方法實現
**********
呼叫父類方法的另外一種方式(知道)
在 Python 2.x 時,如果需要呼叫父類的方法,還可以使用以下方式:
父類名.方法(self)
*這種方式,目前在 Python 3.x 還支援這種方式
*這種方法 不推薦使用,因為一旦 父類發生變化,方法呼叫位置的 類名 同樣需要修改
提示
*在開發時,父類名 和 super() 兩種方式不要混用
*如果使用 當前子類名 呼叫方法,會形成遞迴呼叫,出現死迴圈
**********

class Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("我會飛")

    def bark(self):

        # 1. 針對子類特有的需求,編寫程式碼
        print("神一樣的叫喚...")

        # 2. 使用 super(). 呼叫原本在父類中封裝的方法
        super().bark()

        # 父類名.方法(self)
        #Dog.bark(self)
        # 注意:如果使用子類呼叫方法,會出現遞迴呼叫 - 死迴圈!
        # XiaoTianQuan.bark(self)

        # 3. 增加其他子類的程式碼
        print("$%^*%^$%^#%$%")


xtq = XiaoTianQuan()

# 如果子類中,重寫了父類的方法
# 在使用子類物件呼叫方法時,會呼叫子類中重寫的方法
xtq.bark()

1.3 父類的 私有屬性 和 私有方法
a.子類物件 不能 在自己的方法內部,直接 訪問 父類的 私有屬性 或 私有方法
b.子類物件 可以通過 父類 的 公有方法 間接 訪問到 私有屬性 或 私有方法
***私有屬性、方法 是物件的隱私,不對外公開,外界 以及 子類 都不能直接訪問
***私有屬性、方法 通常用於做一些內部的事情

class A:

    def __init__(self):

        self.num1 = 100
        self.__num2 = 200

    def __test(self):
        print("私有方法 %d %d" % (self.num1, self.__num2))


class B(A):

    def demo(self):

        # 1. 在子類的物件方法中,不能訪問父類的私有屬性
        # print("訪問父類的私有屬性 %d" % self.__num2)

        # 2. 在子類的物件方法中,不能呼叫父類的私有方法
        # self.__test()
        pass

# 建立一個子類物件
b = B()
print(b)

b.demo()

# 在外界不能直接訪問物件的私有屬性/呼叫私有方法
# print(b.__num2)
# b.__test()
class A:

    def __init__(self):

        self.num1 = 100
        self.__num2 = 200

    def __test(self):
        print("私有方法 %d %d" % (self.num1, self.__num2))

    def test(self):
        print("父類的公有方法 %d" % self.__num2)

        self.__test()


class B(A):

    def demo(self):

        # 1. 在子類的物件方法中,不能訪問父類的私有屬性
        # print("訪問父類的私有屬性 %d" % self.__num2)

        # 2. 在子類的物件方法中,不能呼叫父類的私有方法
        # self.__test()

        # 3. 訪問父類的公有屬性
        print("子類方法 %d" % self.num1)

        # 4. 呼叫父類的公有方法
        self.test()
        pass

# 建立一個子類物件
b = B()
print(b)

b.demo()
# 在外界訪問父類的公有屬性/呼叫公有方法
# print(b.num1)
# b.test()

# 在外界不能直接訪問物件的私有屬性/呼叫私有方法
# print(b.__num2)
# b.__test()

02. 多繼承

子類 可以擁有 多個父類,並且具有 所有父類 的 屬性 和 方法

2.1 多繼承的使用注意事項
問題的提出
如果 不同的父類 中存在 同名的方法,子類物件 在呼叫方法時,會呼叫 哪一個父類中的方法呢?(最近的父類方法)
提示:開發時,應該儘量避免這種容易產生混淆的情況! —— 如果 父類之間 存在 同名的屬性或者方法,應該 儘量避免 使用多繼承

Python 中的 MRO —— 方法搜尋順序(知道)
*Python 中針對 類 提供了一個 內建屬性 __mro__ 可以檢視 方法 搜尋順序
*MRO 是 method resolution order,主要用於 在多繼承時判斷 方法、屬性 的呼叫 路徑
print(C.__mro__)
輸出結果
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

**在搜尋方法時,是按照 __mro__ 的輸出結果 從左至右 的順序查詢的
**如果在當前類中 找到方法,就直接執行,不再搜尋
**如果 沒有找到,就查詢下一個類 中是否有對應的方法,如果找到,就直接執行,不再搜尋
**如果找到最後一個類,還沒有找到方法,程式報錯

2.2 新式類與舊式(經典)類
object 是 Python 為所有物件提供的 基類,提供有一些內建的屬性和方法,可以使用 dir 函式檢視
***新式類:以 object 為基類的類,推薦使用
***經典類:不以 object 為基類的類,不推薦使用
***在 Python 3.x 中定義類時,如果沒有指定父類,會 預設使用 object 作為該類的 基類 —— Python 3.x 中定義的類都是 新式類
***在 Python 2.x 中定義類時,如果沒有指定父類,則不會以 object 作為 基類

新式類 和 經典類 在多繼承時 —— 會影響到方法的搜尋順序
為了保證編寫的程式碼能夠同時在 Python 2.x 和 Python 3.x 執行!
今後在定義類時,如果沒有父類,建議統一繼承自 object

class A:

    def test(self):
        print("test 方法")


class B:

    def demo(self):
        print("demo 方法")


class C(A, B):
    """多繼承可以讓子類物件,同時具有多個父類的屬性和方法"""
    pass


# 建立子類物件
c = C()

c.test()
c.demo()
class A:

    def test(self):
        print("A --- test 方法")

    def demo(self):
        print("A --- demo 方法")

class B:

    def test(self):
        print("B --- test 方法")

    def demo(self):
        print("B --- demo 方法")


class C(B, A):
    """多繼承可以讓子類物件,同時具有多個父類的屬性和方法"""
    pass


# 建立子類物件
c = C()

c.test()
c.demo()

# 確定C類物件呼叫方法的順序
print(C.__mro__)
You are never too old to set another goal or to dream a new dream!!!