Python面向對象之繼承


面向對象三大特性

  1. 封裝 根據職責將屬性和方法封裝到一個抽象的類中;
  2. 繼承 實現代碼的重用,西安通的代碼不需要重復的編寫;
  3. 多態 不同的對象調用相同的方法,產生不同的執行結果,增加代碼的靈活度。

單繼承

使用繼承前的代碼

class Animal:
    def eat(self):
        print("吃")

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


class Dog:
    def eat(self):
        print("吃")

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

    def bark(self):
        print("犬吠")


dog = Animal()
dog.eat()
dog.sleep()

jinmao = Dog()
jinmao.eat()
jinmao.bark()

雖然可以通過代碼復制來減少工作量,但代碼重復卻很多。

繼承的概念和語法

繼承的概念:子類擁有父類所有的屬性和方法;

繼承的語法

class 類名(父類名):
	pass
  • 子類繼承自父類,可以直接享用父類中已經開發好的方法,不需要再次開發;
  • 子類中應該根據職責,封裝子類中特有的屬性和方法;

單繼承示例

class Animal:
    def eat(self):
        print("吃")

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

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


class Dog(Animal):
    def bark(self):
        print("犬吠")


jinmao = Dog()
jinmao.eat()  # 吃
jinmao.bark()  # 叫

繼承相關術語

子類=派生類;
父類=基類;
繼承=派生;

例如:
Dog類是Animal類的子類,Animal類是Dog類的父類,Dog類從Animal類繼承;

繼承的傳遞性

  • C類繼承自B類,B類又繼承自A類;
  • 那么C類就擁有B類和A類所有的屬性和方法;
  • 總結就是:子類擁有父類及父類的父類的所有封裝的屬性與方法。

繼承傳遞示例

class Animal:
    def eat(self):
        print("吃")

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


class Dog(Animal):
    def bark(self):
        print("犬吠")


class Corgi(Dog):
    def leg(self):
        print("腿很短")


keji = Corgi()
# 子類使用自己的方法
keji.leg()
# 子類使用父類的方法
keji.bark()
# 子類使用父類的父類的方法
keji.eat()

繼承傳遞的分支問題

雖然貓和狗都繼承自動物類,但狗的子類柯基並不能調用貓類的方法,因為柯基並沒有繼承自貓類;

方法重寫

應用場景

  • 當父類中的方法滿足不了子類的需求時,可以對方法進行重寫;
  • 重寫父類的方法有兩種:
    1.覆蓋父類的方法;
    2.對父類方法進行擴展;

覆蓋父類的方法

如果在開發中,父類的方法實現和子類的方法實現,完全不同,就可以使用覆蓋在方法,在子類中重新編寫父類的方法實現;

覆蓋方式:在子類中定義一個和父類重名的方法並且實現;

重寫之后,在運行時,只會調用子類中重寫的方法,而不會再調用父類中封裝的方法;

class Dog(Animal):
    def bark(self):
        print("犬吠")


class Corgi(Dog):
    def leg(self):
        print("腿很短")
        
    def bark(self):
        print("柯基吠")


keji = Corgi()
# 子類使用自己的方法
keji.leg()
# 子類使用重寫父類的方法
keji.bark()

子類中擴寫父類的方法

如果在開發中,子類的方法實現,包含了父類的方法實現,即原本父類封裝的方法是子類方法的一部分,這時候就可以使用子類擴寫父類的方法。

擴寫方式:

  1. 在子類中重寫父類的方法;
  2. 在需要的位置,調用父類的方法,用super().父類方法名
  3. 編寫子類方法其他的代碼

關於super

  1. 在python中,super是一個特殊的類;
  2. super()就是使用super類創建出來的對象;
  3. 經常使用的場景就是,重寫父類方法時,調用在父類中封裝的方法;

擴寫示例

class Dog(Animal):
    def bark(self):
        print("犬吠")


class Corgi(Dog):
    def leg(self):
        print("腿很短")

    def bark(self):
        # 1.針對子類特有的需求,編寫代碼
        print("柯基吠")
        # 2.在需要的位置,調用父類的方法,用super().父類方法名
        super().bark()
        # 3.編寫子類方法其他的代碼
        print("...")


keji = Corgi()
# 子類使用自己的方法
keji.leg()
# 子類使用 擴展父類的方法
keji.bark()

# 腿很短
# 柯基吠
# 犬吠
# ...

使用父類名調用父類方法(了解)

在python2.x中,如果需要調用父類的方法,還可以用這種方式:

父類名.方法(self)

在python3中,仍然支持這種方法,但不推薦使用,因為一旦父類發生變化,調用位置的父類名同樣需要修改

注意:

  1. 在開發中,父類名和super()兩種方法不要混用;
  2. 如果使用當前子類名調用方法,會形成遞歸調用,形成死循環;

使用父類名調用父類方法示例

class Dog(Animal):
    def bark(self):
        print("犬吠")


class Corgi(Dog):
    def leg(self):
        print("腿很短")

    def bark(self):
        print("柯基吠")
        # 使用父類名調用父類方法,不推薦使用
        Dog.bark(self)
        # 注意,如果使用子類調用方法,會出現遞歸調用,形成死循環
        # Corgi.bark(self)
        
        print("...")


keji = Corgi()
keji.leg()
keji.bark()

# 腿很短
# 柯基吠
# 犬吠
# ...

多繼承

多繼承概念和語法

概念:子類可以具有多個父類,並且具有多個父類的屬性和方法;

語法:

class 子類名(父類1,父類2,...):
	pass

作用:多繼承可以讓子類同時具有多個父類的屬性和方法;

多繼承示例

class A:
    def test_a(self):
        print("test_a")


class B:
    def test_b(self):
        print("test_b")


class C(A, B):
    pass


c = C()

c.test_a()  # test_a
c.test_b()  # test_b

多繼承注意事項

  • 如果兩個父類之間具有同名屬性或方法,應該盡量避免使用多繼承;
  • 如果兩個父類之間具有同名屬性或方法,子類在調用方法時,會優先使用先繼承那個父類的方法;

多繼承方法調用順序示例

class A:
    def test(self):
        print("test_a")

    def demo(self):
        print("demo_a")


class B:
    def test(self):
        print("test_b")

    def demo(self):
        print("demo_b")


class C(A, B):
    pass


c = C()

c.test()  # test_a
c.demo()  # demo_a

我們把C的繼承父類順序換一下

class A:
    def test(self):
        print("test_a")

    def demo(self):
        print("demo_a")


class B:
    def test(self):
        print("test_b")

    def demo(self):
        print("demo_b")


class C(B, A):
    pass


c = C()

c.test()  # test_b
c.demo()  # demo_b

MRO--方法搜索順序

__mro__的作用:在創建對象的類,以及繼承的父類中,查找要調用的方法的 順序;

  • python中針對類提供了一個內置屬性__mro__可以查看方法搜索順序;
  • mro主要用於多繼承時,判斷方法,屬性的調用順序;

__mro__方法使用示例

# 假設C類繼承自B和A
print(C.__mro__)
輸出結果:
# (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
  • 在搜索方法時,是按照__mro__搜索結果從左到右的順序查找的;
  • 如果在當前類中找到方法,就直接執行,不再查找;
  • 如果沒有找到,就查找下一個類中是否有對應的方法,如果找到方法,就直接執行,不再查找;
  • 如果找到最后一個類,還沒有找到方法,就報錯。

__mro__方法使用完整示例

class A:
    def test(self):
        print("test_a")

    def demo(self):
        print("demo_a")


class B:
    def test(self):
        print("test_b")

    def demo(self):
        print("demo_b")


class C(B, A):
    pass


c = C()

c.test()  # test_b
c.demo()  # demo_b

# 確定C類的調用方法順序
print(C.__mro__)  # (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

新式類和經典(舊式)類

  • 在ipython中,添加了object就是新式類,沒添加就是經典類;可以用dir(對象名)查看新式類和經典類的內置方法;
  • 在ipython3下,就算你沒添加object,python解釋器也會給你加上,默認就是新式類;

object是python為所有對象提供的基類,提供有一些內置的方法和屬性,可以用dir函數查看,dir(對象名);

新式類:以object為基類的類,推薦使用;
經典類:不以object為基類的類,不推薦使用;

  • 在python3中定義類時,如果沒有指定父類,會默認使用object作為該類的基類--python3中定義的類都是新式類;
  • 在python2中,定義類時,如果沒有指定父類,則不會以object作為基類;
    新式類和經典類在多繼承時,會影響方法的搜索順序;

為了保證編寫的代碼能同時在python2和python3下運行,以后在定義類時,如果沒有父類,建議統一繼承object類;

class 類名(object):
	pass

在ipython下查看內置方法

查看新式類內置方法

class A(object):
	pass

a = A()
dir(a)

查看舊式類內置方法

class B:
	pass

b = B()
dir(b)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM