15 - 多繼承&多態📄目錄1 多繼承1.1 子類可以擁有多個父類,並且具有所有父類的屬性和方法1.2 不同的父類存在同名的方法1.3 方法的搜索順序(了解)1.4 多繼承的弊端⚠️2 多態2.1 多態的前提2.2 多態性:一種調用方式,不同的執行結果3 靜態方法 @staticmethod
4 類方法 @classmethod
5 方法的總結6 __init__()
和__new__()
6.1 __init__()
:初始化對象6.2 __new__()
:object基類提供的內置的靜態方法6.3 一個對象的實例化過程6.4 總結:__init__()
和__new__()
導航連結:
xxxxxxxxxx
class 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):
pass
son = Child()
son.money()
輸出結果:
xxxxxxxxxx
100,000 inheritance can be inherited
⚠️⚠️ 實際開發時,需要盡量避免這種情況
xxxxxxxxxx
class 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):
pass
son = Child()
son.money()
輸出結果:
xxxxxxxxxx
150,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__
的輸出結果,按照從左往右的順序查找。
從當前類中找到了方法,就會直接執行,不再搜索。
如果找到最後一個類,還沒有找到對應方法,程序會報錯
容易引發衝突
會導致代碼設計的複雜度增加
指同一種行為具有不同的表現形式
繼承(發生在繼承關係的基礎之上)
重寫
多態的特點:
不關注對象的類型,關注對象具有的行為,也就是對象的實例方法是否同名
多態的好處:可以增加代碼的外部調用靈活度,讓代碼更加通用,兼容性比較強
不同的子類對象,調用相同的父類方法,會產生不同的執行結果
多態即同一東西(+)的不同表現形式:
xxxxxxxxxx
print(10+10) # 算術運算符:實現整型之間的相加操作
print("10"+"10") # 字符串拼接:實現字符串之間的拼接操作
xxxxxxxxxx
class 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()
輸出結果:
xxxxxxxxxx
Cat can mew
Dog can bark
xxxxxxxxxx
class 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)
輸出結果:
xxxxxxxxxx
Animal can move
Mammal can lactate
Bird can fly
👉🏻 test函數傳入不同的對象,執行不同對象的eat方法
@staticmethod
使用@staticmethod來進行修飾,靜態方法沒有self,cls參數的限制
靜態方法與類無關,可以被轉換成函數使用
xxxxxxxxxx
class Person(object):
def study():
print('Human can study')
# 靜態方法既可以使用對象訪問,也可以使用類訪問
Person.study()
pe = Person()
pe.study()
輸出結果:
xxxxxxxxxx
Human can study
Human can study
xxxxxxxxxx
class Person(object):
# 這裡可以加東西,就不算靜態方法
def study(name):
print(f'{name} will study')
# 靜態方法既可以使用對象訪問,也可以使用類訪問
Person.study('Antonio')
pe = Person()
pe.study('Antonio') # 調用方法時傳參數
輸出結果:
xxxxxxxxxx
Antonio will study
Antonio will study
💡 取消不必要的參數傳遞,有利於減少不必要的內存佔用和性能消耗
@classmethod
使用裝飾器@classmethod來標識為類方法,對於類方法,第一個參數必須是類對象,一般是以cls作為第一個參數。
格式:
xxxxxxxxxx
class 類名:
def 方法名(cls, 其他形參):
方法體
類方法內部可以訪問類屬性,或者調用其他類方法
xxxxxxxxxx
class 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'>
sleeping
Antonio
💡 使用場合:
當方法中需要使用類對象(如訪問私有類屬性等),定義類方法
類方法一般是配合類屬性使用
實例方法:方法內部訪問實例屬性,方法內部可以通過「類名.類屬性名」來訪問類屬性
靜態方法:方法內部不需要訪問實例屬性和類性。如果要訪問類屬性,通過「類名.類屬性名」訪問,不能訪問實例屬性
類方法:方法內部只需要訪問類屬性,可以通過「cls.類屬性名」訪問類屬性,不能訪問實例屬性
xxxxxxxxxx
class 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()
輸出結果:
xxxxxxxxxx
Victoria在玩遊戲
18
I am Victoria
My name is Victoria
Victoria
__init__()
和__new__()
__init__()
:初始化對象xxxxxxxxxx
class Test(object):
def __init__(self):
print('這是__init__')
te = Test()
輸出結果:
xxxxxxxxxx
這是__init__
__new__()
:object基類提供的內置的靜態方法作用:
在內存中為對象分配空間
返回對象的引用
xxxxxxxxxx
class 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__()
,對對象進行初始化
xxxxxxxxxx
class 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)
輸出結果:
xxxxxxxxxx
This 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 - 單例模式&魔法方法 |