python中的類與對象2
class Chinese: # 類的創(chuàng)建
eye = 'black' # 類屬性的創(chuàng)建
def __init__(self,hometown): # 類的初始化方法
self.hometown = hometown # 實例屬性的創(chuàng)建
print('程序持續(xù)更新中……') # 初始化中的語句
def born(self): # 實例方法的創(chuàng)建
print('我生在%s。'%(self.hometown)) # 方法的具體語句
bazhan = Chinese('廣東') # 類的實例化
print(bazhan.eye) # 打印實例的屬性(從類傳遞的)
bazhan.born() # 實例方法的調(diào)用
類的繼承和定制
繼承
- 我們通過事物的歸屬關(guān)系删掀,使信息的傳遞更為高效翔冀。聽到“Python是一種計算機語言”,我們就知道Python可以編程披泪;看到“云浮市在廣東省”纤子,我們就明白云浮市在中國南方
- 我們也可以用一句話,讓計算機知道:A類屬于B類款票,自然也擁有了B類的所有屬性和方法控硼。這句話在編程里就是:A類繼承了B類。
- 在Python中艾少,我們的習(xí)慣表述是:A類是B類的子類卡乾,而B類是A類的父類(或超類)。
- 類的繼承缚够,讓子類擁有了父類擁有的所有屬性和方法幔妨。
定制
- 只有繼承的話,子類只是父類的復(fù)制而已谍椅。我們需要了解另一個重要的概念:類的定制误堡。
- 子類也可以在繼承的基礎(chǔ)上進行個性化的定制,包括:(1)創(chuàng)建新屬性雏吭、新方法锁施;(2)修改繼承到的屬性或方法。
- 類的定制杖们,不僅可以讓子類擁有新的功能悉抵,還能讓它有權(quán)修改繼承到的代碼
- 當(dāng)我們談定制時,已經(jīng)包含了繼承胀莹。畢竟基跑,類的定制的前提是繼承,而定制的加入讓類的繼承不僅僅只是單純的復(fù)制而已描焰。這也是我們創(chuàng)建子類的意義
類的繼承如何寫
繼承的基礎(chǔ)語法
- 子類繼承的屬性和方法媳否,也會傳遞給子類創(chuàng)建的實例
# 例
class Chinese:
eye = 'black'
def eat(self):
print('吃飯栅螟,選擇用筷子。')
class Cantonese(Chinese):
# 通過繼承篱竭,Chinese類有的力图,Cantonese類也有
pass
# 驗證子類可以繼承父類的屬性和方法,進而傳遞給子類創(chuàng)建的實例
yewen = Cantonese()
# 子類創(chuàng)建的實例掺逼,從子類那間接得到了父類的所有屬性和方法
print(yewen.eye)
# 子類創(chuàng)建的實例吃媒,可調(diào)用父類的屬性
yewen.eat()
# 子類創(chuàng)建的實例,可調(diào)用父類的方法
- 通過一個小括號吕喘,子類就能輕輕松松地?fù)碛懈割愃鶕碛械囊磺凶改恰2挥脧?fù)制大段大段的代碼,只要一個括號氯质,就能復(fù)用整塊代碼募舟。
- 很多類在創(chuàng)建時也不帶括號,如class Chinese闻察,實際上拱礁,class Chinese:在運行時相當(dāng)于class Chinese(object):。而object辕漂,是所有類的父類呢灶,我們將其稱為根類(可理解為類的始祖)。
- 我們可以用一個函數(shù)來驗證這一點:函數(shù)isinstance()钉嘹,可以用來判斷某個實例是否屬于某個類鸯乃。
print(isinstance(1,int))
# 判斷1是否為整數(shù)類的實例
print(isinstance(1,str))
print(isinstance(1,(int,str)))
# 判斷實例是否屬于元組里幾個類中的一個
# 閱讀完代碼再運行。
class Chinese:
pass
class Cantonese(Chinese):
pass
gonger = Chinese()
# 宮二跋涣,電影《一代宗師》女主飒责,生于東北
yewen = Cantonese()
# 葉問,電影《一代宗師》男主仆潮,生于廣東
print('\n驗證1:子類創(chuàng)建的實例同時也屬于父類')
print(isinstance(gonger,Chinese))
print(isinstance(yewen,Chinese))
print('\n驗證2:父類創(chuàng)建的實例不屬于子類。')
print(isinstance(gonger,Cantonese))
print('\n驗證3:類創(chuàng)建的實例都屬于根類遣臼。')
print(isinstance(gonger,object))
print(isinstance(yewen,object))
- 在類的繼承中性置,不僅子類屬于父類,子類所創(chuàng)建的實例實際上也同時屬于父類揍堰。
- 父類可以被無限個子類所繼承(這一點好比類的屬性方法可以傳遞給無限個實例)
類的繼承之多層繼承
# 例
class Earthman:
eye_number = 2
# 中國人繼承了地球人
class Chinese(Earthman):
eye_color = 'black'
# 廣東人繼承了中國人鹏浅,同時也繼承了地球人。
class Cantonese(Chinese):
pass
yewen = Cantonese()
print(yewen.eye_number)
print(yewen.eye_color)
- 實例yewen可以調(diào)用父類Chinese和父類的父類Earthman中的屬性屏歹∫遥可得結(jié)論:子類創(chuàng)建的實例可調(diào)用所有層級父類的屬性和方法。
- 多層繼承蝙眶,屬于繼承的==深度拓展==季希。而下面要講的多重繼承褪那,則是繼承的寬度拓展。
類的繼承之多重繼承
- 一個類式塌,可以同時繼承多個類博敬,語法為class A(B,C,D):
- 假設(shè)我們將“出生在江蘇,定居在廣東的人”設(shè)為一個類Yuesu峰尝,那么偏窝,它的創(chuàng)建語句則為class Yuesu(Yue,Su)。
- class Yuesu(Yue,Su)括號里Yue和Su的順序是有講究的武学。和子類更相關(guān)的父類會放在更左側(cè)
- “出生在江蘇祭往,定居在廣東的人”在穿著和飲食等方面會更接近廣東人,所以將 Yue 放在 Su 的左側(cè)
- 所以火窒,廣東人創(chuàng)建的實例在調(diào)用屬性和方法時硼补,會先在左側(cè)的父類中找,找不到才會去右側(cè)的父類找沛鸵。(可理解為“就近原則”)
class Su:
born_city = 'Jiangsu'
wearing = 'thick' # 穿得較厚
def diet(self):
print('我們愛吃甜括勺。')
class Yue:
settle_city = 'Guangdong'
wearing = 'thin' # 穿得較薄
def diet(self):
print('我們吃得清淡。')
class Yuesu(Yue,Su):
pass
xiaoming = Yuesu()
print(xiaoming.wearing)
print(xiaoming.born_city)
xiaoming.diet()
# 越靠近子類(即越靠左)的父類曲掰,越親近疾捍,越優(yōu)先考慮。子類調(diào)用屬性和方法時栏妖,會先在靠左的父類里找乱豆,找不到才往右找。
- 多層繼承和多重繼承的結(jié)合吊趾,讓繼承的類擁有更多的屬性和方法宛裕,且能更靈活地調(diào)用。進而论泛,繼承的力量也得以放大了很多倍揩尸。
class C0:
name = 'C0'
class C2(C0):
num = 2
class C1:
num = 1
class C3:
name = 'C3'
class C4(C1,C2,C3):
pass
ins = C4()
print(ins.name) # 打印出C0
print(ins.num) # 打印出1
- 可以發(fā)現(xiàn)就近原則中的一個細(xì)節(jié):多重繼承中,若某父類還有父類的話屁奏,會先繼續(xù)往上找到頂岩榆。例如代碼中的ins.name調(diào)用的是C2的父類C0的值而非 C3。
類的定制如何寫
定制坟瓢,可以新增代碼
# 例
class Chinese:
eye = 'black'
def eat(self):
print('吃飯勇边,選擇用筷子。')
class Cantonese(Chinese): # 類的繼承
native_place = 'guangdong' # 類的定制
def dialect(self): # 類的定制
print('我們會講廣東話折联。')
yewen = Cantonese()
print(yewen.eye)
# 父類的屬性能用
print(yewen.native_place)
# 子類的定制屬性也能用
yewen.eat()
# 父類的方法能用
yewen.dialect()
# 子類的定制方法也能用
- 我們可以在子類下新建屬性或方法粒褒,讓子類可以用上父類所沒有的屬性或方法。這種操作诚镰,屬于定制中的一種:新增代碼奕坟。
定制祥款,也可重寫代碼
- 例題:已知中國的陸地面積,也知道廣東的陸地面積占比為1.88%执赡。
class Chinese:
def land_area(self,area):
print('我們居住的地方镰踏,陸地面積是%d萬平方公里左右。'% area)
class Cantonese(Chinese):
# 直接對方法進行重寫
def land_area(self,area):
print('我們居住的地方沙合,陸地面積是%d萬平方公里左右奠伪。'% int(area * 0.0188))
gonger = Chinese()
yewen = Cantonese()
gonger.land_area(960)
yewen.land_area(960)
#兩個類都有個各自的land_area()方法,但有些冗余
class Chinese:
def land_area(self,area):
print('我們居住的地方,陸地面積是%d萬平方公里左右首懈。'% area)
class Cantonese(Chinese):
# 間接對方法進行重寫
def land_area(self, area, rate = 0.0188):
Chinese.land_area(self, area * rate)
# 直接繼承父類方法绊率,再調(diào)整參數(shù)。
gonger = Chinese()
yewen = Cantonese()
gonger.land_area(960)
yewen.land_area(960)
- 子類繼承父類方法的操作是在def語句后接父類.方法(參數(shù))究履,如上述代碼的第八滤否、九行。
- 父類方法land_area中的說法改變最仑,子類也不用去動藐俺,因為子類直接繼承了父類的方法。只不過泥彤,在繼承的基礎(chǔ)上欲芹,通過參數(shù)的調(diào)整完成了定制。
- 參數(shù)的調(diào)整吟吝,可以增加參數(shù)(如 rate)菱父,也可以改變參數(shù)的默認(rèn)值
class Chinese:
def land_area(self,area):
print('我們居住的地方,陸地面積是%d萬平方公里左右剑逃。' % area)
class Cantonese(Chinese):
# 為參數(shù) area 設(shè)置默認(rèn)值浙宜。
def land_area(self, area = 960, rate = 0.0188):
Chinese.land_area(self, area * rate)
yewen = Cantonese()
yewen.land_area()
# 兩個參數(shù)都有默認(rèn)值,所以可以這么調(diào)用蛹磺。
- 例題:通過參數(shù)默認(rèn)值的改變粟瞬,完成子類的定制,讓程序的運行結(jié)果為“雷猴萤捆!歡迎來到廣東亩钟。”
class Chinese:
def __init__(self, greeting = '你好', place = '中國'):
self.greeting = greeting
self.place = place
def greet(self):
print('%s鳖轰!歡迎來到%s。' % (self.greeting, self.place))
class Cantonese(Chinese):
def __init__(self, greeting = '雷猴', place = '廣東'):
Chinese.__init__(self, greeting, place)
yewen = Cantonese()
yewen.greet()
練習(xí)
練習(xí)一
- 練習(xí)要求:每個人都有好幾個不同的身份扶镀,且不同身份都附帶一些特定的特征(屬性)和行為(方法)蕴侣。例如,有這樣一群人:在學(xué)校時被歸在老師臭觉,臉是嚴(yán)肅的昆雀;親子關(guān)系中(parenthood)則被歸到父親辱志,臉是甜蜜的。
class Teacher:
face = 'serious'
job = 'teacher'
class Father:
face = 'sweet'
parenthood = 'dad'
class TeacherMore(Teacher, Father):
pass
class FatherMore(Father, Teacher):
face = 'gentle'
time3 = TeacherMore()
time4 = FatherMore()
print(time3.face)
print(time4.face)
練習(xí)二
- 練習(xí)要求:練習(xí)會先提供一個類狞膘,用以記錄學(xué)生學(xué)習(xí) Python 的投入時間和有效時間揩懒。需要你創(chuàng)建一個子類,為某一類學(xué)生提供定制化的記錄方案挽封。
class Student:
def __init__(self, name, job=None, time=0.00, time_effective=0.00):
self.name = name
self.job = job
self.time = time
self.time_effective = time_effective
def count_time(self, hour, rate):
self.time += hour
self.time_effective += hour * rate
class Programmer(Student):
def __init__(self, name):
Student.__init__(self, name, job='programmer', time=0.00, time_effective=0.00)
def count_time(self, hour, rate=1):
Student.count_time(self, hour, rate)
student1 = Student('韓梅梅')
student2 = Programmer('李雷')
print(student1.job)
print(student2.job)
student1.count_time(10, 0.8)
student2.count_time(10)
print(student1.time_effective)
print(student2.time_effective)