構(gòu)造方法也是函數(shù)整份,但是它調(diào)用的時(shí)間是確定的,當(dāng)一個(gè)對象被創(chuàng)建之后火俄,會立即調(diào)用構(gòu)造方法讲冠。
原來我在寫objective-c和C#時(shí)都會寫構(gòu)造方法,用來初始化類中屬性谱仪。而且需要顯示的調(diào)用。
Python中有一類魔法方法(特殊方法)嗦随,初始化用到是init敬尺。
class Person:
def __init__(self):
self.name = "nzh"
self.age = 25
p1 = Person()
print("p1的姓名:{0},年齡:{1}".format(p1.name, p1.age))
在init函數(shù)中悬而,我們設(shè)定了兩個(gè)屬性,name和age笨奠。并且直接賦值般婆。
在調(diào)用Person()函數(shù)時(shí),它會隱式調(diào)用init()函數(shù)乡范,然后Person類的對象中的屬性就被設(shè)置了啤咽。
init()函數(shù)中默認(rèn)會傳遞一個(gè)self的參數(shù),self代表的是對象自己瓶佳,那么生成p1對象時(shí)調(diào)用的Person()函數(shù)時(shí)鳞青,這個(gè)self就代表了p1,self會對當(dāng)前對象進(jìn)行綁定厚脉。
上面的例子我們是把屬性值都定死了胶惰,這不夠靈活。如果想讓自定義屬性的值精钮,就需要給init()函數(shù)傳遞參數(shù)轨香。
# 構(gòu)造一個(gè)用戶信息
class User:
def __init__(self, name, age):
self.name = name
self.age = age
user1 = User("nzh", 25)
print("user1用戶的名字:{0},年齡:{1}".format(user1.name, user1.age))
Python中有一個(gè)魔法方法叫del,相當(dāng)于析構(gòu)函數(shù)科雳,它的作用是在被垃圾回收之前調(diào)用脓杉,但是發(fā)生的時(shí)間不可預(yù)知,應(yīng)該盡力避免使用尿赚。
構(gòu)造方法在繼承中的使用
現(xiàn)在有兩個(gè)類蕉堰,A和B屋讶。B是A的子類。
A中定義了一個(gè)hello方法斩芭,B中沒有定義任何內(nèi)容乐疆,當(dāng)B的對象調(diào)用hello方法時(shí),同樣可以調(diào)用迁筛。因?yàn)閔ello方法是從父類A中繼承過來的耕挨。
這里面跟構(gòu)造函數(shù)有很大關(guān)系,因?yàn)锽的構(gòu)造方法調(diào)用了A的構(gòu)造方法贪庙,如果不是這樣止邮,B中就不能調(diào)用hello方法。
那么如何調(diào)用父類的構(gòu)造方法屈扎?有兩種方式撩匕。
調(diào)用未綁定的超類構(gòu)造方法
在Python3.0之前會用到的方法,現(xiàn)在更流行用super函數(shù)模蜡,稍后說super扁凛,先說未綁定。
class Bird():
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry == True:
print("吃點(diǎn)東西...")
self.hungry = False
else:
print("我不餓卤妒,謝謝")
class SongBird(Bird):
def __init__(self):
self.sound = "this is a song"
def sing(self):
print(self.sound)
s = SongBird()
s.sing()
s.eat()
這里SongBird類的對象不能調(diào)用eat方法,就是因?yàn)樵赟ongBird初始化的時(shí)候沒有調(diào)用超類的構(gòu)造方法纬朝,可以修改SongBird的初始化函數(shù)init()
class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound = "this is a song"
def sing(self):
print(self.sound)
加了一句Bird.init(self)就能調(diào)用了Bird類中的eat方法了骄呼?背后發(fā)生了一些事情蜓萄。
在調(diào)用一個(gè)實(shí)例的方法時(shí),該方法的self參數(shù)會被自動綁定到實(shí)例上(這叫綁定方法)辟犀。如果只是調(diào)用Bird.init()绸硕,而沒有給它傳遞self參數(shù),那么Bird也不知道綁定了哪個(gè)實(shí)例出嘹,而且會引發(fā)一個(gè)TypeError錯誤咬崔。
正如上圖所示,錯誤信息顯示init()方法少了一個(gè)必要的參數(shù)self只祠。
如果直接調(diào)用Bird類的Bird.init呢丸升?(看起來像是一個(gè)屬性,而非方法)
同樣可以看到墩剖,提示沒有hungry屬性岭皂,沒有提供self參數(shù)沼头,實(shí)例就不會被綁定,這樣就可以隨便提供self參數(shù)土至。
例子中是吧SongBird的self傳給了Bird的init函數(shù)(不知道這么理解對不對)陶因,這種方法就是未綁定方法(unbound)
使用super函數(shù)
首先得知道super函數(shù)只能在新式類中使用垂蜗,如果你使用過老版本的python那么就不行了。至少是2.2以后烘苹,因?yàn)閟uper是2.2新加入的特性片部。
修改SongBird類:
class SongBird(Bird):
def __init__(self):
super(SongBird, self).__init__()
self.sound = "this is a song"
def sing(self):
print(self.sound)
為什么一個(gè)super就解決了這些問題呢档悠?其實(shí)super函數(shù)很只能,不管你的這個(gè)類繼承了多少層超類黍图,它只需要使用一次super函數(shù)就可以調(diào)用超類中的方法奴烙,前提是這些超類中都要使用super函數(shù)剖张。
super函數(shù)返回的是一個(gè)super對象搔弄,它負(fù)責(zé)對調(diào)用的方法進(jìn)行解析丰滑,以至于我們可以成功調(diào)用超類中的方法。
有多層繼承關(guān)系時(shí)炫刷,子類從下至上逐層尋找郁妈,比如D是C的子類噩咪,C是B的子類,B是A的子類涨享。
那么繼承關(guān)系就是這樣的A->B->C->D仆百。
D中先到C中找,如果C中沒有該方法栏账,再去B中找栈源,最后再去A中找甚垦。找不到會報(bào)錯涣雕,異常類型為AttributeError。