python中,類通過繼承的方式,子類可以獲得父類的非私有屬性和非私有方法,不需要自己再重新實現。
繼承可以多層繼承,即可以多代繼承。也可以多繼承,即乙個子類可以繼承多個父類。
一、菱形繼承簡介
在多層繼承和多繼承同時使用的情況下,就會出現複雜的繼承關係,多重多繼承。
其中,就會出現菱形繼承。如下圖所示。
菱形繼承也叫鑽石繼承,在這種結構中,當d類的物件使用乙個屬性時,首先會在d類中查詢是否有該屬性和方法,如果沒有則會到父類中查詢,如果還沒有則會繼續往父類的父類中查詢。
根據這種關係,如果d類中沒有找到屬性和方法,是去b類中查詢還是去c類中查詢?
假設是去b類中查詢,如果b類中也沒有找到,下一步是去c類中還是a類中呢?
這些問題都是菱形繼承所帶來的問題,接下來我們來看python中是怎麼處理的。
二、菱形繼承的初始化問題
class
electrical
(object):
def__init__
(self, name)
: self.name = name
print
('electrical init'
)class
phone
(electrical)
:def
__init__
(self, name, price)
: electrical.__init__(self, name)
self.price = price
print
('phone init'
)class
computer
(electrical)
:def
__init__
(self, name, config)
: electrical.__init__(self, name)
self.config = config
print
('computer init'
)class
huawei
(phone, computer)
:def
__init__
(self, name, price, config)
: phone.__init__(self, name, price)
computer.__init__(self, name, config)
print
('huawei init')
h = huawei(
'huawei'
,100
,'i7'
)執行結果:
electrical init
phone init
electrical init
computer init
huawei init
上面的phone類和computer類都繼承了electrical類,huawei類既繼承了phone類又繼承了computer類,這就形成了乙個菱形的繼承關係。
在建立huawei類物件時,electrical類的__init__方法執行了兩遍,也就是說在phone類向上繼承時執行了,在computer類向上繼承時也執行了,這顯然是不應該發生的。
三、通過super解決初始化問題
class
electrical
(object):
def__init__
(self, name)
: self.name = name
print
('electrical init'
)class
phone
(electrical)
:def
__init__
(self, price,
*args)
:super
(phone, self)
.__init__(
*args)
self.price = price
print
('phone init'
)class
computer
(electrical)
:def
__init__
(self, config,
*args)
:super
(computer, self)
.__init__(
*args)
self.config = config
print
('computer init'
)class
huawei
(phone, computer)
:def
__init__
(self, name, price, config)
:super
(huawei, self)
.__init__(name, price, config)
print
('huawei init')
h = huawei(
'huawei'
,100
,'i7'
)執行結果:
electrical init
computer init
phone init
huawei init
通過super方法,我們解決了electrical初始化兩次的問題,現在的繼承關係就是正常的了。
注意:在phone類和computer類中給super()後的init方法傳引數時,應使用*args,因為huawei有三個引數,但是phone類和computer類都只有兩個引數,所以引數個數不正確會報錯。
四、菱形繼承的繼承順序
class
electrical
(object):
defchat
(self)
:print
('chat with friend in electrical!'
)def
watch_movie
(self)
:print
('watch movie in electrical!'
)def
game
(self)
:print
('play game in electrical!'
)class
phone
(electrical)
:def
game
(self)
:print
('play game in phone!'
)class
computer
(electrical)
:def
watch_movie
(self)
:print
('watch movie in computer!'
)def
game
(self)
:print
('play game in computer!'
)class
huawei
(phone, computer)
:pass
h = huawei(
)h.game(
)h.watch_movie(
)h.chat(
)執行結果:
play game in phone!
watch movie in computer!
chat with friend in electrical!
在上面的繼承關係中,huawei類中乙個方法也沒有實現,所以類物件呼叫方法都是要去父類中找。
game()方法在三個類中都實現了,呼叫了phone類中的方法,說明最先會去phone類中查詢。
watch_movie()方法在phone類中也沒有實現,呼叫了computer類中的方法,說明第二個會去computer類中查詢。
chat()方法在phone類和computer類中都沒有實現,呼叫了electrical類中的方法,說明最後會去electrical類中查詢。
注意:在繼承時,如果小括號()中先寫computer再寫phone,則兩個類的繼承順序就會調換。
由此,我們可以得出菱形繼承的繼承順序了。如下圖所示。
五、__mro__方法檢視繼承順序
根據上面的案例,我們已經知道了菱形繼承中的繼承順序了。
這種繼承順序是遵循廣度優先演算法的。也就是說,多層多繼承時,先在父級中按先後順序查詢,然後在到父級的父級中查詢。
這樣,繼承順序已經很清晰了,不過,這還需要我們人工來識別繼承順序。如果繼承關係非常複雜,像一張網一樣,我們再去人工識別繼承順序將會非常困難,並且容易出錯。
在python中,已經定義了乙個魔法方法來幫助我們檢視類的繼承順序,這個方法就是__mro__方法。
print(huawei.mro)
執行結果:(,
,,,)
mro是 method resolution order (方法解析順序)的簡寫,我們可以直接列印類的__mro__方法來獲取類的繼承順序。
注意:__mro__只能通過類物件來使用,不能通過例項物件來使用。
python語法基礎 初始化 繼承
寫了一些程式,基本上都是直接def函式 然後在main方法中 呼叫 但是在一些應用程式中 會有基本語法的使用 初始化,繼承 初始化 1.在程式執行時一定執行一次的操作 2.python中初始化init 引數第乙個必須要加self 3.對變數進行賦值 繼承 子類繼承父類 1.子類繼承父類 直接 子類 ...
繼承與初始化
當存在繼承的情況時,各變數的初始化情況變得更為複雜了 不關區域性變數的事 我們有必要梳理一下。class insect private static int x1 printinit static insect.x1 initialized public int x2 printinit shape...
繼承時的初始化
例 class insect static int x1 prt static insect.x1 static int prt string s public class beetle extends insect static int x2 prt static beetle.x2 public...