繼承
雖然子類(lèi)Bosi沒(méi)有__init__()方法,但是父類(lèi)有,所以子類(lèi)在繼承父類(lèi)時(shí),這個(gè)方法也被繼承了。所以只要?jiǎng)?chuàng)建了Bosi的對(duì)象,就默認(rèn)執(zhí)行繼承過(guò)來(lái)的__init__()方法。
子類(lèi)在繼承的時(shí)候,在定義類(lèi)的時(shí)候,小括號(hào)()中為父類(lèi)的名字,父類(lèi)的屬性、方法都會(huì)繼承給子類(lèi)。
當(dāng)子類(lèi)和父類(lèi)擁有同一方法是,調(diào)用誰(shuí)的方法。觀察如下代碼:
子類(lèi)和父類(lèi)同有__init__()方法,在對(duì)象調(diào)用時(shí),子類(lèi)的__init__()方法會(huì)覆蓋父類(lèi)的__init__()方法。
關(guān)于對(duì)象調(diào)用時(shí)的地址和繼承調(diào)用時(shí)的地址,觀察如下代碼:
可以看出,他們的地址是一樣的。
私有的屬性和方法都不能被繼承,也不能被對(duì)象直接調(diào)用,可以通過(guò)方法訪(fǎng)問(wèn)。一般情況下,私有的屬性和方法都是不對(duì)外公布的,往往用來(lái)做內(nèi)部的事情,起到安全的作用。
一個(gè)子類(lèi)不僅可以單一繼承,也可以多繼承。當(dāng)一個(gè)子類(lèi)有多個(gè)父類(lèi)時(shí),具體的操作代碼如下:
從以上的例子可以看出,當(dāng)存在多個(gè)父類(lèi)時(shí),且這些父類(lèi)擁有同名的方法,子類(lèi)會(huì)按照繼承的順序去調(diào)用方法,而不會(huì)發(fā)生父類(lèi)方法的重寫(xiě)。
如果想子類(lèi)父類(lèi)都有該方法,如何重寫(xiě)子類(lèi)覆蓋的父類(lèi)方法,方式有兩種。具體代碼如下:
使用super().父類(lèi)方法名()可以實(shí)現(xiàn)重寫(xiě)父類(lèi)方法,但因?yàn)槭前蠢^承順序調(diào)用的父類(lèi)方法,所以父類(lèi)F2()中的test ()方法不會(huì)被調(diào)用。如何在不修改繼承順序的情況下調(diào)用父類(lèi)F2()中的test ()方法。代碼如下:
通過(guò)父類(lèi)名.父類(lèi)方法名(self)可以實(shí)現(xiàn)想要訪(fǎng)問(wèn)的父類(lèi)方法。
對(duì)于屬性的賦值,如果在子類(lèi)中對(duì)特殊屬性賦值時(shí),將會(huì)覆蓋父類(lèi)對(duì)于共有屬性的定義,所以可以采用以上的方法對(duì)屬性賦值:
通過(guò)以上代碼,不僅完成了對(duì)Dog()這一類(lèi)特殊屬性的賦值,也完成了父類(lèi)Animal()的通用屬性的賦值。
類(lèi)屬性、實(shí)例屬性
class?Student():
name?=?'Tony'
__age?=?18
stu1?=?Student()
print(stu1.name)輸出Tony
print(Student.name)輸出Tony
print(stu1.__age)報(bào)錯(cuò),不能在類(lèi)外通過(guò)實(shí)例對(duì)象訪(fǎng)問(wèn)私有的類(lèi)屬性
print(Student.__age)報(bào)錯(cuò),不能在類(lèi)外通過(guò)類(lèi)對(duì)象訪(fǎng)問(wèn)私有的類(lèi)屬性
class?People(object):
#類(lèi)屬性
address?=?'山東'
def?__init__(self):
self.name?=?'xiaowang'
self.age?=?20
p?=?People()
p.age?=12
print(p.address)
print(p.name)
print(p.age)
print(People.address)
print(People.name)
print(People.age)
輸出結(jié)果如上所示。如何通過(guò)實(shí)例對(duì)象修改類(lèi)屬性?
如果需要在類(lèi)外修改類(lèi)屬性,必須通過(guò)類(lèi)對(duì)象去引用然后進(jìn)行修改。如果通過(guò)實(shí)例對(duì)象去引用,會(huì)產(chǎn)生一個(gè)同名的實(shí)例屬性,這種方式修改的是實(shí)例屬性,不會(huì)影響到類(lèi)屬性,并且之后如果通過(guò)實(shí)例對(duì)象去引用該名稱(chēng)的屬性,實(shí)例屬性會(huì)強(qiáng)制屏蔽掉類(lèi)屬性,即引用的是實(shí)例屬性,除非刪除了該實(shí)例屬性。
類(lèi)方法
是類(lèi)對(duì)象所擁有的方法,需要用修飾器@classmethod來(lái)標(biāo)識(shí)其為類(lèi)方法,對(duì)于類(lèi)方法,第一個(gè)參數(shù)必須是類(lèi)對(duì)象,一般以cls作為第一個(gè)參數(shù)(當(dāng)然可以用其他名稱(chēng)的變量作為其第一個(gè)參數(shù),但是大部分人都習(xí)慣以'cls'作為第一個(gè)參數(shù)的名字,就最好用'cls'了),能夠通過(guò)實(shí)例對(duì)象和類(lèi)對(duì)象去訪(fǎng)問(wèn)。
class?People(object):
country?=?'china'
#類(lèi)方法,用classmethod來(lái)進(jìn)行修飾
@classmethod
def?getCountry(cls):
return?cls.country
p?=?People()
print(p.getCountry())#可以用過(guò)實(shí)例對(duì)象引用
print(People.getCountry())????#可以通過(guò)類(lèi)對(duì)象引用
類(lèi)方法還可以對(duì)類(lèi)屬性進(jìn)行修改
class?People(object):
country?=?'china'
#類(lèi)方法,用classmethod來(lái)進(jìn)行修飾
@classmethod
def?getCountry(cls):
return?cls.country
@classmethod
def?setCountry(cls,country):
cls.country?=?country
p?=?People()
print(p.getCountry())?????????#可以用過(guò)實(shí)例對(duì)象引用
print(People.getCountry())????#可以通過(guò)類(lèi)對(duì)象引用
p.setCountry('japan')
print(p.getCountry())
print(People.getCountry())
靜態(tài)方法
需要通過(guò)修飾器@staticmethod來(lái)進(jìn)行修飾,靜態(tài)方法不需要多定義參數(shù)
class?People(object):
country?=?'china'
@staticmethod
#靜態(tài)方法
def?getCountry():
return?People.country
print(People.getCountry())
從類(lèi)方法和實(shí)例方法以及靜態(tài)方法的定義形式就可以看出來(lái),類(lèi)方法的第一個(gè)參數(shù)是類(lèi)對(duì)象cls,那么通過(guò)cls引用的必定是類(lèi)對(duì)象的屬性和方法;而實(shí)例方法的第一個(gè)參數(shù)是實(shí)例對(duì)象self,那么通過(guò)self引用的可能是類(lèi)屬性、也有可能是實(shí)例屬性(這個(gè)需要具體分析),不過(guò)在存在相同名稱(chēng)的類(lèi)屬性和實(shí)例屬性的情況下,實(shí)例屬性?xún)?yōu)先級(jí)更高。靜態(tài)方法中不需要額外定義參數(shù),因此在靜態(tài)方法中引用類(lèi)屬性的話(huà),必須通過(guò)類(lèi)對(duì)象來(lái)引用。