第二十四章 面向对象------属性
最常見的是直接繼承一個(gè)已經(jīng)存在的類
當(dāng)你想要?jiǎng)?chuàng)建一個(gè)新的類 發(fā)現(xiàn)這個(gè)類中的一些 在某一個(gè)類中已經(jīng)存在
那就沒有必要從頭開始寫 ,可以直接繼承已有的類 然后做補(bǔ)充
class MyList(list):
def __init__(self,element_cls):
?當(dāng)你覆蓋了init方法時(shí)
?不要忘記調(diào)用super().init函數(shù)讓父類完成原有的初始化操作
super().__init__()
self.element_cls = element_cls
def append(self, object):
# if isinstance(object,str)
if object.__class__ == self.element_cls:
super().append(object)
else:
print("只能存儲(chǔ)%s類型!" % self.element_cls.__name__)
?
2.super()的問題 mro列表
python支持多繼承 一個(gè)類可以同時(shí)繼承多個(gè)父類
好處是更加靈活
問題是:屬性的查找順序該怎么確定
# 問題:多繼承時(shí)如果多個(gè)父類中出現(xiàn)了同名的屬性/函數(shù)
# 你不能用眼睛去判斷查找順序 ,需要使用mro列表來查看真正的繼承順序
# 總結(jié):super在訪問父類屬性時(shí) 是按照mro列表一層層往上找的
#測試
class A:
def test(self):
print("from A")
super().test() # 應(yīng)該報(bào)錯(cuò)..... 但是卻執(zhí)行成功了
class B:
def test(self):
print("from B")
pass
class C(A,B):
pass
c = C()
c.test()
#最后:盡量不要使用多繼承
組合:
"""組合:
指的是 一個(gè)類把另一個(gè)類的對象作為自己的屬性 就稱之為組合
無處不在
當(dāng)你定義一個(gè)類 并且這個(gè)類擁有某種類型的屬性時(shí) 就稱之為組合
?
都是用用來重用代碼的方式:
組合描述的是 什么擁有什么的關(guān)系 ? 學(xué)生 有 書 學(xué)生有手機(jī)
基礎(chǔ)描述的是 什么是什么的關(guān)系 ? ? 麥兜是豬 ? 豬豬俠也是豬
"""
?
?
# class Person:
# ? ? def __init__(self,name):
# ? ? ? ? self.name = name
#
#
# p = Person("rose")
# print(p.name)
?
?
class PC:
? ?def open_app(self,app_name):
? ? ? ?print("open %s" % app_name)
?
class OldBoyStudent:
? ?def __init__(self,PC,notebook):
? ? ? ?self.PC = PC
? ? ? ?self.notebook = notebook
? ?pass
?
pc = PC()
notebook = PC()
?
?
stu = OldBoyStudent(pc,notebook)
3.菱形繼承問題 ***
?新式類與經(jīng)典類
# 在py2中 A就是一個(gè)經(jīng)典類
# class A:
# pass
# 如果你的代碼需要兼容py2 那應(yīng)該顯式的繼承object 無論是直接還是間接繼承
class B(object):
pass
class A(B):
pass
class A:
# a = 1
pass
class B(A):
# a = 2
pass
class C(A):
# a = 3
pass
class D(A):
# a = 4
pass
class E(B,C,D):
# a = 5
pass
e1 = E()
# print(e1.a)
# 新式類的順序
# E B C D A object
# 經(jīng)典類的順序
# E B A C D
# print(E.mro())
注意:經(jīng)典類沒有mro列表
4.接口 ***
接口是什么
例如USB
電腦內(nèi)部具備USB相應(yīng)的功能 如果要使用的話 就必須給外界提供一個(gè)使用方式,該方式就稱之為接口 ,
在程序中功能通常是用函數(shù)來表示, 對于外界而言 無需清楚函數(shù)時(shí)如何實(shí)現(xiàn)的 只要知道函數(shù)名即可, 這個(gè)函數(shù)名稱就可以稱之為接口
外界調(diào)用接口就能完成某個(gè)任務(wù)
接口其實(shí)就是一組功能的定義,但是只清楚函數(shù)名稱,而沒有具體的實(shí)現(xiàn)細(xì)節(jié)
相當(dāng)于是一套規(guī)范,
例如USB 規(guī)定了接口的外觀,大小,以及每條線路的功能是什么
硬件開發(fā)商照著這個(gè)USB協(xié)議來生產(chǎn)設(shè)備,就可以被電腦使用
class USB:?
? ?def open(self):
? ? ? ?pass
?
? ?def close(self):
? ? ? ?pass
?
? ?def work(self):
? ? ? ?pass
好處:
使用接口可以提高程序的擴(kuò)展性
只要對象按照接口規(guī)定方法來實(shí)現(xiàn),使用者就可以無差別使用所有對象
接口與抽象類
抽象:
指的是 不清楚 不具體 看不懂
抽象方法:
指的是 沒有函數(shù)體的方法 用@abc.abstractmethod 裝飾器
如果類中具備抽象方法 那么這個(gè)類就稱之為抽象類
抽象類的特點(diǎn):
不能直接實(shí)例化 必須有子類覆蓋了所有抽象方法后才能實(shí)例化子類
與接口的區(qū)別:
?
import abc?
class Test(metaclass=abc.ABCMeta):
?
? ?
?
問題:如果接口的子類沒有實(shí)現(xiàn)接口中的方法,那是沒有任何意義的
抽象類之所以出現(xiàn)的意義:通過抽象類來強(qiáng)行限制子類必須覆蓋所有的抽象方法
鴨子類型
說如果一個(gè)對象叫聲像鴨子,走路像鴨子,長得像鴨子,那它就是鴨子
是python 推薦的方式,python不喜歡強(qiáng)行限制你
?class PC():
?
? ?def conntent_device(self, usb_device):
? ? ? ?usb_device.open()
? ? ? ?usb_device.work()
? ? ? ?usb_device.close()
?
class Mouse:
? ?# 實(shí)現(xiàn)接口規(guī)定的所有功能
? ?def open(self):
? ? ? ?print("mouse opened")
?
? ?def work(self):
? ? ? ?print("mouse working...")
?
? ?def close(self):
? ? ? ?print("mouse closed")
?
mouse = Mouse()
pc = PC()
?
pc.conntent_device(mouse)
?
?
?
class KeyBoard:
? ?def open(self):
? ? ? ?print("KeyBoard opened")
?
? ?def work(self):
? ? ? ?print("KeyBoard working...")
?
? ?def close(self):
? ? ? ?print("KeyBoard closed")
?
key1 = KeyBoard()
?
# 如果key1的特征和行為都像USB設(shè)備 那就把它當(dāng)做USB設(shè)備來使用
# 對于使用者而言可以不用關(guān)心這個(gè)對象是什么類,是如如何是實(shí)現(xiàn),
pc.conntent_device(key1)
?
?
案例2:
class Linux:? ?def read_data(self,device):
? ? ? ?data = device.read()
? ? ? ?return data
?
? ?def write_data(self,device,data):
? ? ? ?device.write(data)
?
class Disk:
? ?def read(self):
? ? ? ?print("disk reading....")
? ? ? ?return "這是一個(gè)磁盤上的數(shù)據(jù)"
?
? ?def write(self,data):
? ? ? ?print("disk writing %s..." % data)
?
class UP:
? ?def read(self):
? ? ? ?print("disk reading....")
? ? ? ?return "這是一個(gè)U盤上的數(shù)據(jù)"
?
? ?def write(self,data):
? ? ? ?print("disk writing %s..." % data)
?
?
l = Linux()
?
d = Disk()
data = l.read_data(d)
l.write_data(d,"這是一個(gè)數(shù)據(jù)....")
?
?
up1 = UP()
l.read_data(up1)
l.write_data(up1,"一個(gè)數(shù)據(jù)...")
例如linux 有一句話叫一切皆文件
之所以這么設(shè)計(jì)是為了提高擴(kuò)展性,讓Linux可以無差別對待任何設(shè)備!
今日的知識(shí)點(diǎn):
1.繼承的另一種使用方法
繼承一個(gè)已經(jīng)存在的類 并擴(kuò)展新方法 或修改原來的方法
2.super() 是按照mro列表來查找屬性的
3.組合 一個(gè)類把另一個(gè)類的對象作為屬性
菱形繼承的問題
?
經(jīng)典類:不是object的子類 僅在py2中出現(xiàn)
深度優(yōu)先
新式類:object的子類 py3中都是新式類
先深度 直到有一個(gè)公共父類時(shí),查找其他路線(基于C3算法)
5.接口是一套協(xié)議規(guī)范,具體表現(xiàn):一堆只有方法聲明而沒有實(shí)現(xiàn)體的方法
6.抽象類:具備抽象方法的類 抽象方法時(shí)沒有實(shí)現(xiàn)體的方法 不能直接實(shí)例化 通過abc模塊來實(shí)現(xiàn)
抽象類既可以以后抽象方法也可以有普通方法
而接口中全都是抽象方法
接口的出現(xiàn)是為了提高擴(kuò)展性,抽象類是為類限制子類必須按照接口要求的來實(shí)現(xiàn)
鴨子類型
對于一個(gè)優(yōu)秀的程序員,即時(shí)沒有接口和抽象類的限制,也能寫出一個(gè)具備擴(kuò)展性的程序
就如何做到:鴨子類型
鴨子類型:這個(gè)對象 長的想鴨子 叫聲像鴨子 走路像鴨子 那它就是鴨子
就可以把它當(dāng)成鴨子來使用
轉(zhuǎn)載于:https://www.cnblogs.com/sry622/p/10883704.html
總結(jié)
以上是生活随笔為你收集整理的第二十四章 面向对象------属性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jenkins构建ant项目
- 下一篇: 读懂SAP Leonardo物联网平台