本節(jié)開始,我們將討論面向?qū)ο缶幊痰娜筇卣鳎悍庋b、繼承和多態(tài)。下面,我們將由簡至難,依次討論封裝、繼承、多態(tài)。
一. 封裝?enclosure
- 封裝:指隱藏類的實(shí)現(xiàn)細(xì)節(jié),讓使用者不用關(guān)心這些細(xì)節(jié);
- 目的:讓使用者通過盡可能少的方法(或?qū)傩?操作對象;
- 如何封裝:通過私有屬性和方法;
- 私有屬性和方法:
- 以雙下劃線'__'開頭,不以雙下劃線結(jié)尾的標(biāo)識(shí)符為私有成員;
- 私有成員只能用此類的方法進(jìn)行訪問和修改
- 擴(kuò)展:了解java的讀者可能知道,java中使用了private、default、protected、public關(guān)鍵字,實(shí)現(xiàn)了更豐富的封裝;
- 示例:
class A:
"""用私有屬性和私有方法封裝屬性和方法"""
__dd = 300
def __init__(self):
# 創(chuàng)建私有屬性,此屬性在類外無法訪問
self.__e = 100
@staticmethod
# 私有方法
def __en():
print('私有方法__en被調(diào)用!')
@classmethod
def get__dd(cls):
print("私有的類變量__dd:{}".format(cls.__dd))
def info(self):
print('A的實(shí)例方法info訪問私有屬性__e:', self.__e)
# 調(diào)用私有方法
self.__en()
if __name__ == "__main__":
a = A()
a.info()
a.__class__.get__dd()
# print(a.__e) #AttributeError: 'A' object has no attribute '__e'
# print(a.__en()) #AttributeError: 'A' object has no attribute '_en'
# 創(chuàng)建新變量(屬性)
a.__e = 'hello'
print(a.__e)
print(a.__dict__)
運(yùn)行結(jié)果:
二.?繼承 inheritance 和 派生 derived
- 什么是繼承/派生:
- 繼承是指從已有的類中派生出新的類,新類具有原類的行為,并能擴(kuò)展新的行為;
- 派生類就是從一個(gè)已有的類衍生出新的類,在新的類上可以添加新的屬性和行為;
- 作用:
- 用繼承派生機(jī)制,可以將一些共有功能加在基類中,實(shí)現(xiàn)代碼共享;(共有的屬性和方法向上提,形成抽象)
- 在不改變超類的代碼基礎(chǔ)上改變原有功能
- 名詞:
- 基類 base class / 超類 super class / 父類 father class
- 派生類 derived class / 子類
1. 單繼承
- 語法:
?? ??? ?class 類名(
基類名
):
?? ??? ??? ?語句塊
- 說明:單繼承是派生類由一個(gè)基類衍生而來的
- 類的__base__屬性:用來記錄此類的父類
- 子類對象可以當(dāng)成父類對象來使用:
- 示例
class Human:
"""此類用來描述人類的共同行為"""
@staticmethod
def say(what):
print('說:', what)
@staticmethod
def walk(distance):
print('走了', distance, '公里')
class Student(Human):
"""描述學(xué)生的共同行為"""
@staticmethod
def study(subject):
print('學(xué)習(xí)', subject)
class Teacher(Student):
@staticmethod
def teach(content):
print('正在教', content)
if __name__ == "__main__":
h1 = Human()
h1.say('Today is a good day.')
h1.walk(5)
print("#########################")
s1 = Student()
s1.say('How are you?')
s1.walk(5)
s1.study('Python')
print("#########################")
t1 = Teacher()
t1.say('I am a teacher.')
t1.walk(3)
t1.teach('講解繼承派生')
t1.study('滑冰')
運(yùn)行結(jié)果:
2. 覆蓋 override
- 概念:覆蓋是指在有繼承關(guān)系的類中,子類中實(shí)現(xiàn)了與父類同名的方法,子類實(shí)例調(diào)用該方法時(shí),實(shí)際調(diào)用的是子類中覆蓋版本的方法,這種現(xiàn)象被稱為覆蓋;
- super 函數(shù):
- super(type, obj):返回綁定超類的實(shí)例(要求obj必須為type類型的實(shí)例);
- super():返回綁定超類的實(shí)例,等同于super(__class__,實(shí)例方法的第一個(gè)參數(shù)self);
- super()必須放在方法內(nèi)調(diào)用
- 作用:返回綁定超類的實(shí)例,用超類的實(shí)例來調(diào)用其父類的覆蓋方法;
- 顯示調(diào)用父類的構(gòu)造方法:當(dāng)子類中實(shí)現(xiàn)了__init__方法,父類的構(gòu)造方法并不會(huì)被調(diào)用,此時(shí)需要顯示調(diào)用父類的構(gòu)造方法:super().__init__(參數(shù))
- 示例1:在方法內(nèi)使用super()
class Human:
def __init__(self, n, a):
self.name = n
self.age = a
def info(self):
print('name:', self.name)
print('age:', self.age)
class Student(Human):
def __init__(self, n, a, s):
# 顯示調(diào)用父類的初始化方法
super().__init__(n, a)
self.score = s
def info(self):
"""# 覆蓋,子類只負(fù)責(zé)干子類的事情"""
super().info()
print('score:', self.score)
if __name__ == "__main__":
h1 = Human('Alex', 22)
h1.info()
s1 = Student('Thomas', 25, 99)
s1.info()
示例2:
class A:
def work(self):
print('A.work被調(diào)用!')
class B(A):
"""用super構(gòu)造函數(shù)來間接調(diào)用父類的覆蓋版本的方法"""
def work(self):
print('B.work被調(diào)用!')
def super_work(self):
"""此方法先調(diào)用一下子類的方法,再調(diào)用一下父類的方法"""
self.work()
# super().work() #調(diào)用父類的work,不能在方法外調(diào)用
# super(B,self).work()
super(__class__, self).work()
if __name__ == "__main__":
a = A()
a.work()
print("###################")
b = B()
b.work()
# 方法外部,使用super()函數(shù)調(diào)用B的父類A的work方法
print("###################")
super(B, b).work()
print("###################")
b.super_work()
示例2運(yùn)行結(jié)果:
2. 多繼承?multiple inheritance
- 概念:多繼承是指一個(gè)子類繼承自兩個(gè)或兩個(gè)以上的基類;
- 語法:class類名(基類名1, 基類名2...);
- 說明:
- 一個(gè)子類同時(shí)繼承自多個(gè)父類,父類中的方法可以同時(shí)被繼承下來;
- 如果兩個(gè)父類中有同名的方法,則在子類中又沒有覆蓋此方法時(shí),調(diào)用結(jié)果難以確定
- 問題(缺陷):多繼承可能會(huì)有標(biāo)識(shí)符(名字空間)沖突的問題;
- 多繼承的MRO(Method Resolution Order)問題:
- '類'的__mro__屬性:用來記錄屬性或方法的查找順序;
- 示例:
class A:
def m(self):
print('A.m()')
class B:
def m(self):
print('B.m()')
class C:
def m(self):
print('C.m()')
class D(A, B, C):
def m(self):
super(A, self).m()
super(B, self).m()
super().m()
print('D.m()')
if __name__ == "__mian__":
d = D()
d.m()
print(D.__mro__)
運(yùn)行結(jié)果:
結(jié)果分析: super()函數(shù)根據(jù)MRO順序來查找方法
類D同時(shí)繼承自類A,B, C,且這些類中都有方法m,在調(diào)用super時(shí),方法的查找順序是按照D.__mro__屬性指定的順序;在D.m()中首先調(diào)用的是super(A, self).m(),A的上一個(gè)是B,因此首先打印B.m();同理,super(B, self).m(),B的上一個(gè)是C,因此打印C.m()。
3. 用于類的函數(shù):issubclass(cls, class_or_tuple)
- 判斷一個(gè)類是否繼承自其它的類,如果此類是 class 或 tuple 中的一個(gè)派生子類,則返回 True ,否則返回 False;
- 一切類型都是 object 的子類
三.?多態(tài) polymorphic
- 什么是多態(tài):多態(tài)是指在有繼承/派生關(guān)系的類中,調(diào)用“基類對象的方法”,實(shí)際能調(diào)用子類的覆蓋方法,這種現(xiàn)象被稱為多態(tài);
- 說明:
- 多態(tài)“調(diào)用的方法與對象相關(guān)”,不與類型相關(guān);
- Python全部對象都只有運(yùn)行時(shí)狀態(tài)(動(dòng)態(tài)),沒有'C++語言'里的編譯時(shí)狀態(tài)(靜態(tài))
- 示例:
class Shape:
def draw(self):
print('Shape的draw()被調(diào)用')
class Point(Shape):
def draw(self):
print('正在畫一個(gè)點(diǎn)')
class Circle(Point):
def draw(self):
print('正在畫一個(gè)圓')
def my_draw(s):
"""示意多態(tài)的使用"""
# s.draw調(diào)用誰是在運(yùn)行時(shí)由s的類動(dòng)態(tài)決定
s.draw()
if __name__ == "__main__":
my_draw(Shape())
my_draw(Point())
my_draw(Circle())
運(yùn)行結(jié)果:
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
