對(duì)于使用過C++的人來說踏枣,構(gòu)造函數(shù)與析構(gòu)函數(shù)不會(huì)陌生刑赶。
構(gòu)造函數(shù)在對(duì)象創(chuàng)建時(shí)被調(diào)用谆膳,析構(gòu)函數(shù)在對(duì)象被銷毀時(shí)被調(diào)用。而Python中也有類似的特殊函數(shù):__new__
脯倒,__init__
实辑,__del__
。
其中__new__
與__init__
共同構(gòu)成了C++中的構(gòu)造函數(shù)藻丢,__del__
為析構(gòu)函數(shù)剪撬。
__new__
在對(duì)象被創(chuàng)建時(shí)被調(diào)用,而__init__
在對(duì)象被初始化時(shí)被調(diào)用悠反。
-
__new__
的第一個(gè)參數(shù)是對(duì)象本身残黑,其他的參數(shù)是用來直接傳遞給__init__
方法馍佑。__new__
方法相當(dāng)不常用,但是當(dāng)繼承一個(gè)不可變的類型(比如一個(gè)tuple或者string)時(shí)梨水,它將派上用場(chǎng)拭荤。但這已經(jīng)超出了基礎(chǔ)的范圍,所以暫且不提疫诽。 -
__init__
十分常見舅世,用以初始化對(duì)象。當(dāng)父類擁有該函數(shù)奇徒,而繼承的子類想要調(diào)用父類的__init__
雏亚,應(yīng)該使用super().__init__()
而不是父類名.__init__()
,以此來避免多繼承問題摩钙。
__del__
在對(duì)象被銷毀時(shí)被調(diào)用评凝,但它并不是實(shí)現(xiàn)del
語法的內(nèi)置函數(shù)。它定義的是對(duì)象被銷毀時(shí)的行為腺律,但由于Python的GC問題奕短,所以對(duì)象銷毀的時(shí)刻無法由編寫者完全自控,所以用處也較少匀钧。
附:多繼承問題
多繼承問題是一個(gè)古老的 Feature(當(dāng)一個(gè)Bug沒法修的時(shí)候就叫 Feature)翎碑。讓我們運(yùn)行如下代碼
class A():
def __init__(self):
print("進(jìn)入A…")
print("離開A…")
class B(A):
def __init__(self):
print("進(jìn)入B…")
A.__init__(self)
print("離開B…")
class C(A):
def __init__(self):
print("進(jìn)入C…")
A.__init__(self
print("離開C…")
class D(B, C):
def __init__(self):
print("進(jìn)入D…")
B.__init__(self)
C.__init__(self)
print("離開D…")
d = D()
結(jié)果如下
進(jìn)入D…
進(jìn)入B…
進(jìn)入A…
離開A…
離開B…
進(jìn)入C…
進(jìn)入A…
離開A…
離開C…
離開D…
可以看到,A的__init__
被調(diào)用了兩次之斯。而這并不是我們期待的日杈。為此在有些語言里,禁止了多繼承佑刷。
Python的解決方法是:使用super()
調(diào)用父類方法莉擒。
class A():
def __init__(self):
print("進(jìn)入A…")
print("離開A…")
class B(A):
def __init__(self):
print("進(jìn)入B…")
super().__init__()
print("離開B…")
class C(A):
def __init__(self):
print("進(jìn)入C…")
super().__init__()
print("離開C…")
class D(B, C):
def __init__(self):
print("進(jìn)入D…")
super().__init__()
print("離開D…")
d = D()
運(yùn)行結(jié)果如下
進(jìn)入D…
進(jìn)入B…
進(jìn)入C…
進(jìn)入A…
離開A…
離開C…
離開B…
離開D…
這樣A的__init__
只被調(diào)用了一次