15 - 多繼承&多態📄目錄1 多繼承1.1 子類可以擁有多個父類,並且具有所有父類的屬性和方法1.2 不同的父類存在同名的方法1.3 方法的搜索順序(了解)1.4 多繼承的弊端⚠️2 多態2.1 多態的前提2.2 多態性:一種調用方式,不同的執行結果3 靜態方法 @staticmethod4 類方法 @classmethod5 方法的總結6 __init__()和__new__()6.1 __init__():初始化對象6.2 __new__():object基類提供的內置的靜態方法6.3 一個對象的實例化過程6.4 總結:__init__()和__new__()導航連結:

xxxxxxxxxxclass Father(): def money(self): print('100,000 inheritance can be inherited')class Mother(object): def estate(self): print('2 estates can be inherited')class Child(Father, Mother): passson = Child()son.money()輸出結果:
xxxxxxxxxx100,000 inheritance can be inherited⚠️⚠️ 實際開發時,需要盡量避免這種情況

xxxxxxxxxxclass Father(): def money(self): print('100,000 inheritance can be inherited')class Mother(object): def money(self): print('150,000 inheritance can be inherited')class Child(Mother, Father): passson = Child()son.money()輸出結果:
xxxxxxxxxx150,000 inheritance can be inherited如果多個父類具有同名屬性/方法,調用時依據「就近原則」。
即定義子類時,靠前的父類屬性/方法會先被調用(括號內排在前面,就會被優先調用)
💡 python中內置屬性__mro__可以查看方法搜索順序

xxxxxxxxxx# 同時運行3.2的代碼print(Child.__mro__)輸出結果:
xxxxxxxxxx(<class '__main__.Child'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>)搜索方法時,會按照__mro__的輸出結果,按照從左往右的順序查找。
從當前類中找到了方法,就會直接執行,不再搜索。
如果找到最後一個類,還沒有找到對應方法,程序會報錯
容易引發衝突
會導致代碼設計的複雜度增加
指同一種行為具有不同的表現形式
繼承(發生在繼承關係的基礎之上)
重寫
多態的特點:
不關注對象的類型,關注對象具有的行為,也就是對象的實例方法是否同名
多態的好處:可以增加代碼的外部調用靈活度,讓代碼更加通用,兼容性比較強
不同的子類對象,調用相同的父類方法,會產生不同的執行結果
多態即同一東西(+)的不同表現形式:
xxxxxxxxxxprint(10+10) # 算術運算符:實現整型之間的相加操作print("10"+"10") # 字符串拼接:實現字符串之間的拼接操作
xxxxxxxxxxclass Animal(object): def shout(self): print('Animal can shout')class Cat(Animal): def shout(self): print('Cat can mew')class Dog(Animal): def shout(self): print('Dog can bark')cat = Cat()cat.shout()dog = Dog()dog.shout()輸出結果:
xxxxxxxxxxCat can mewDog can bark
xxxxxxxxxxclass Animal(object): def special(self): print('Animal can move')class Mammal(Animal): def special(self): print('Mammal can lactate')class Bird(Animal): def special(self): print('Bird can fly')# 多態性:定義一個統一的接口(以函數形式),一個接口多種實現def test(obj): # obj:形參 obj.special()animal = Animal()mammal = Mammal()bird = Bird()test(animal)test(mammal)test(bird)輸出結果:
xxxxxxxxxxAnimal can moveMammal can lactateBird can fly👉🏻 test函數傳入不同的對象,執行不同對象的eat方法
@staticmethod使用@staticmethod來進行修飾,靜態方法沒有self,cls參數的限制
靜態方法與類無關,可以被轉換成函數使用

xxxxxxxxxxclass Person(object): def study(): print('Human can study')# 靜態方法既可以使用對象訪問,也可以使用類訪問Person.study()pe = Person()pe.study()輸出結果:
xxxxxxxxxxHuman can studyHuman can study
xxxxxxxxxxclass Person(object): # 這裡可以加東西,就不算靜態方法 def study(name): print(f'{name} will study')# 靜態方法既可以使用對象訪問,也可以使用類訪問Person.study('Antonio')pe = Person()pe.study('Antonio') # 調用方法時傳參數輸出結果:
xxxxxxxxxxAntonio will studyAntonio will study💡 取消不必要的參數傳遞,有利於減少不必要的內存佔用和性能消耗
@classmethod使用裝飾器@classmethod來標識為類方法,對於類方法,第一個參數必須是類對象,一般是以cls作為第一個參數。
格式:
xxxxxxxxxxclass 類名: def 方法名(cls, 其他形參): 方法體類方法內部可以訪問類屬性,或者調用其他類方法

xxxxxxxxxxclass Person: name = 'Antonio' # 類屬性 def sleep(cls): print('cls: ', cls) # cls代表類對象本身,類本質上就是一個對象 print('sleeping') print(cls.name) # 訪問類屬性,也可以用print(Person.name)調用print(Person)Person.sleep()輸出結果:
xxxxxxxxxx<class '__main__.Person'>cls: <class '__main__.Person'>sleepingAntonio💡 使用場合:
當方法中需要使用類對象(如訪問私有類屬性等),定義類方法
類方法一般是配合類屬性使用
實例方法:方法內部訪問實例屬性,方法內部可以通過「類名.類屬性名」來訪問類屬性
靜態方法:方法內部不需要訪問實例屬性和類性。如果要訪問類屬性,通過「類名.類屬性名」訪問,不能訪問實例屬性
類方法:方法內部只需要訪問類屬性,可以通過「cls.類屬性名」訪問類屬性,不能訪問實例屬性

xxxxxxxxxxclass Person(object): name = 'Victoria' # 類屬性:類所擁有的屬性 def __init__(self, age): self.age = age # 實例屬性:對象私有的 def play(self): # 實例方法 # 在實例方法中訪問類屬性 print(f'{self.name}在玩遊戲') print(self.age) def info(): print(f'I am {Person.name}') # 靜態方法能夠訪問類屬性,但是無意義 # print(self.age) # 靜態方法不支持訪問實例屬性 def intro(cls): print(f'My name is {cls.name}') # cls代表類對象本身 # print(self.age) # 報錯 print(Person.name)pe = Person(18)pe.play()pe.info()pe.intro()輸出結果:
xxxxxxxxxxVictoria在玩遊戲18I am VictoriaMy name is VictoriaVictoria__init__()和__new__()__init__():初始化對象
xxxxxxxxxxclass Test(object): def __init__(self): print('這是__init__')te = Test()輸出結果:
xxxxxxxxxx這是__init____new__():object基類提供的內置的靜態方法作用:
在內存中為對象分配空間
返回對象的引用

xxxxxxxxxxclass Test(object): def __init__(self): print('這是__init__') def __new__(cls, *args, **kwargs): print('這是__new__') print(cls) # 對父類方法進行擴展 super().方法名() res = super().__new__(cls) # 方法重寫,res裡面保存的是實例對象的引用,__new__()是靜態方法,形參裡面有cls,實參就必須傳cls return res # ‼️:重寫__new__()一定要return super().__new__(cls),否則python解釋器得不到分配空間的對象引用,就不會調用__init__()te = Test()print('te: ', te)# 在這裡定義__new__就相當於在重寫這個方法輸出結果:
xxxxxxxxxx這是__new__<class '__main__.Test'>這是__init__te: <__main__.Test object at 0x10443cc50>執行步驟:先執行__new__(),如果沒有寫__new__(),默認調用object基類提供的__new__(),返回一個實例對象,然後再去調用__init__(),對對象進行初始化

xxxxxxxxxxclass Person(object): def __new__(cls, *args, **kwargs): print("This is __new__") print(f'返回值:{super(Person, cls).__new__(cls)}') return super(Person, cls).__new__(cls) def __init__(self, name, age): self.name = name # 實例屬性 self.age = age print(f'{self.name} is {self.age} years old')pe = Person('John', 20)print(pe)print("--------------")pe2 = Person('James', 21)print(pe2)輸出結果:
xxxxxxxxxxThis is __new__返回值:<__main__.Person object at 0x100971490>John is 20 years old<__main__.Person object at 0x100971490>--------------This is __new__返回值:<__main__.Person object at 0x100a26990>James is 21 years old<__main__.Person object at 0x100a26990>__init__()和__new__()__new__()是創建對象,__init__()是初始化對象
__new__()是返回對象引用,__init__()是定義實例屬性
__new__()是類級別的方法,__init__()是實例級別的方法
| 目的地 | 超連結 |
|---|---|
| 首頁 | 返回主頁 |
| Python學習 | Python學習 |
| 上一篇 | 14 - 封裝、單繼承 |
| 下一篇 | 16 - 單例模式&魔法方法 |