面向对象封装继承多态五大基本原则魔法方法反射
目錄
面向?qū)ο?br /> 三大基本特征
五大基本原則
魔法方法
反射
面向?qū)ο?/h2>
什么是面向?qū)ο?/strong>
使用模板的思想,將世界萬事萬物使用對(duì)象來表示一個(gè)類型
面向?qū)ο蠛兔嫦蜻^程的區(qū)別:
- 面向?qū)ο蟮牟痪褪鞘褂贸绦蛱幚硎虑闀r(shí)以對(duì)象為中心去分析
- 面向過程關(guān)心處理的邏輯、流程等問題,而不關(guān)心事件主體
- 面向?qū)ο蠹疵嫦蛑黧w,所以我們?cè)诮鉀Q問題時(shí)應(yīng)該先進(jìn)行對(duì)象的封裝
面向?qū)ο缶幊讨饕獌?yōu)點(diǎn):
易維護(hù),易擴(kuò)展,效率高
- 其實(shí)OOP編程的主要作用和函數(shù)一樣也是使你的代碼修改和擴(kuò)展變的更容易
- 函數(shù)編程與OOP的主要區(qū)別就是OOP可以使程序更加容易擴(kuò)展和易更改
- OOP編程是利用“類”和“對(duì)象”來創(chuàng)建各種模型來實(shí)現(xiàn)對(duì)真實(shí)世界的描述
- 使用面向?qū)ο缶幊痰脑蛞环矫媸且驗(yàn)樗梢允钩绦蚓S護(hù)和擴(kuò)展變得更簡(jiǎn)單,并且可以大大提高程序開發(fā)效率
- 另外,基于面向?qū)ο蟮某绦蚩梢允顾烁尤菀桌斫饽愕拇a邏輯,從而使團(tuán)隊(duì)開發(fā)變得更從容
Class 類(模板)
1. 一個(gè)類即是對(duì)一類擁有相同屬性的對(duì)象的抽象、藍(lán)圖、原型。
2. 在類中定義了這些對(duì)象的都具備的屬性(variables(data))、共同的方法
Object 對(duì)象(實(shí)例)
1.一個(gè)對(duì)象即是一個(gè)類的實(shí)例化后實(shí)例
2. 一個(gè)類必須經(jīng)過實(shí)例化后方可在程序中調(diào)用,一個(gè)類可以實(shí)例化多個(gè)對(duì)象,每個(gè)對(duì)象亦可以有不同的屬性
3. 就像人類是指所有人,每個(gè)人是指具體的對(duì)象,人與人之前有共性,亦有不同
類中的一些名詞
1. __init__ # 構(gòu)造函數(shù) 2. Self.name = name # 實(shí)例變量、普通屬性 或者叫 普通字段 3. public_object = "public" # 類變量、公有屬性 或則叫 靜態(tài)字段 4. self.__heart= "Normal" # 私有屬性 在外面無法訪問 5. def shot(self) # 類方法三大基本特征
面向?qū)ο蟮娜齻€(gè)基本特征是:封裝、繼承、多態(tài)
封裝
封裝,也就是對(duì)類中屬性和方法進(jìn)行一種封裝,隱藏了實(shí)現(xiàn)細(xì)節(jié)
封裝的目的是增強(qiáng)安全性和簡(jiǎn)化編程,使用者不必了解具體的實(shí)現(xiàn)細(xì)節(jié),而只是要通過外部接口,以特定的訪問權(quán)限來使用類的成員。
封裝的優(yōu)點(diǎn):
- 將變化隔離
- 便于使用
- 提高復(fù)用性
- 提高安全性
繼承
繼承是面向?qū)ο蟮幕咎卣髦?#xff0c;當(dāng)一個(gè)類繼承自另一個(gè)類,它就被稱為一個(gè)子類/派生類,繼承自父類/基類/超類。它會(huì)繼承/獲取所有類成員(屬性和方法)
繼承機(jī)制允許創(chuàng)建分等級(jí)層次的類。繼承就是子類繼承父類的特征和行為,使得子類對(duì)象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
繼承的作用:
繼承能讓我們重新使用代碼,也能更容易的創(chuàng)建和維護(hù)應(yīng)用。
繼承的分類:
- 單繼承:一個(gè)類繼承自單個(gè)基類
- 多繼承:一個(gè)類繼承自多個(gè)基類
- 多級(jí)繼承:一個(gè)類繼承自單個(gè)基類,后者則繼承自另一個(gè)基類
- 分層繼承:多個(gè)類繼承自單個(gè)基類
- 混合繼承:兩種或多種類型繼承的混合
繼承概念的實(shí)現(xiàn)方式有三類:
實(shí)現(xiàn)繼承、接口繼承和可視繼承。
? 實(shí)現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力;
? 接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實(shí)現(xiàn)的能力;
? 可視繼承是指子窗體(類)使用基窗體(類)的外觀和實(shí)現(xiàn)代碼的能力。
多態(tài)
多態(tài)性(polymorphisn)是允許你將父對(duì)象設(shè)置成為和一個(gè)或更多的他的子對(duì)象相等的技術(shù),賦值之后,父對(duì)象就可以根據(jù)當(dāng)前賦值給它的子對(duì)象的特性以不同的方式運(yùn)作。簡(jiǎn)單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。“一個(gè)接口,多種實(shí)現(xiàn)”
實(shí)現(xiàn)多態(tài)的兩種方式:
覆蓋,是指子類重新定義父類的虛函數(shù)的做法。
重載,是指允許存在多個(gè)同名函數(shù),而這些函數(shù)的參數(shù)表不同(或許參數(shù)個(gè)數(shù)不同,或許參數(shù)類型不同,或許兩者都不同)。
多態(tài)的優(yōu)點(diǎn):
五大基本原則
1、單一職責(zé)原則(SRP)
一個(gè)類應(yīng)該有且只有一個(gè)去改變它的理由,這意味著一個(gè)類應(yīng)該只有一項(xiàng)工作。
比如在職員類里,將工程師、銷售人員、銷售經(jīng)理這些情況都放在職員類里考慮,其結(jié)果將會(huì)非常混亂,在這個(gè)假設(shè)下,職員類里的每個(gè)方法都要if else判斷是哪種情況,從類結(jié)構(gòu)上來說將會(huì)十分臃腫。
2、開放封閉原則(OCP)
對(duì)象或?qū)嶓w應(yīng)該對(duì)擴(kuò)展開放,對(duì)修改封閉。
更改封閉即是在我們對(duì)模塊進(jìn)行擴(kuò)展時(shí),勿需對(duì)源有程序代碼和DLL進(jìn)行修改或重新編譯文件!這個(gè)原則對(duì)我們?cè)谠O(shè)計(jì)類的時(shí)候很有幫助,堅(jiān)持這個(gè)原則就必須盡量考慮接口封裝,抽象機(jī)制和多態(tài)技術(shù)!
3、里氏替換原則(LSP)
在對(duì)象 x 為類型 T 時(shí) q(x) 成立,那么當(dāng) S 是 T 的子類時(shí),對(duì)象 y 為類型 S 時(shí) q(y) 也應(yīng)成立。(即對(duì)父類的調(diào)用同樣適用于子類)
4、依賴倒置原則(DIP)
高層次的模塊不應(yīng)該依賴于低層次的模塊,他們都應(yīng)該依賴于抽象。具體實(shí)現(xiàn)應(yīng)該依賴于抽象,而不是抽象依賴于實(shí)現(xiàn)。
5、接口隔離原則(ISP)
不應(yīng)強(qiáng)迫客戶端實(shí)現(xiàn)一個(gè)它用不上的接口,或是說客戶端不應(yīng)該被迫依賴它們不使用的方法,使用多個(gè)專門的接口比使用單個(gè)接口要好的多!
魔法方法
1、何為魔法方法:
Python中,一定要區(qū)分開函數(shù)和方法的含義
- 函數(shù):類外部定義的,跟類沒有直接關(guān)系的;形式: def func(*argv)
- 方法:class內(nèi)部定義的函數(shù)(對(duì)象的方法也可以認(rèn)為是屬性)
- python自動(dòng)產(chǎn)生的(魔法方法):一般形式為 func(),python會(huì)在對(duì)應(yīng)的時(shí)機(jī)自動(dòng)調(diào)用該函數(shù)
- 人為自定義的方法:一般和普通函數(shù)沒有區(qū)別,只是定義在了class中而已
方法與函數(shù)的區(qū)別:
- 方法可認(rèn)為是函數(shù)的特殊情況
- 方法定義在class內(nèi)部
- 方法的第一個(gè)參數(shù)應(yīng)為 cls(類方法) 或者 self(實(shí)例方法)
2、魔法方法調(diào)用的順序
class Student(object):def __new__(cls, *args, **kwargs):print('__new__')return object.__new__(cls) # 必須返回父類的__new__方法,否則不不執(zhí)行__init__方法,無法創(chuàng)建實(shí)例def __init__(self,name):print('__init__')self.name = namedef __str__(self): # 作用:打印實(shí)例時(shí)顯示指定字符串,而不是內(nèi)存地址print('__str__')return self.namedef __call__(self, *args, **kwargs): # 當(dāng)執(zhí)行C()(*args) 或者 s1(*args) 就會(huì)執(zhí)行__call__print('__call__',*args)def __del__(self): # 作用:清除無用的實(shí)例對(duì)內(nèi)存的暫用print('__del__')1、實(shí)例化時(shí)機(jī)會(huì)執(zhí)行__new__、init
2、執(zhí)行 實(shí)例() 就會(huì)執(zhí)行__call__ 方法,并將參數(shù)傳遞給__call__函數(shù)
3、當(dāng)打印實(shí)例時(shí)就會(huì)執(zhí)行 str 方法下返回的字符串(默認(rèn)返回的實(shí)例地址)
4、析構(gòu)方法:當(dāng)刪除實(shí)例時(shí)就會(huì)調(diào)用 del 方法
魔法方法匯總:
基本方法
__int__(self) 定義當(dāng)被 int() 調(diào)用時(shí)的行為 __float__(self) 定義當(dāng)被 float() 調(diào)用時(shí)的行為 __round__(self[, n]) 當(dāng)被round()調(diào)用時(shí)的行為 round(digit[, n]) 將digit數(shù)字保留n位精度 __hash__(self) 定義能被 hash() 調(diào)用的行為 __bytes__(self) 定義被 bytes() 調(diào)用的行為 __bool__(self) 定義被 bool() 調(diào)用的行為 返回True(1) 或 False(0) __format__(self, form) 定義被 format()調(diào)用的行為運(yùn)算符方法
__add__(self, other) 加法:+ __sub__(self, other) 減法:- __mul__(self,other) 乘法:* __truediv(self, other) 除法:/ 注意是 truediv __floordiv(self, other) 整數(shù)除法:// floor()即為向下取整的意思 __mod__(self, other) 求余:% __pow__(self, other[, mod]) 乘方:** pow(x,y[,z]),若無Z,則為 return x**y若有Z,則為 return x**y%z __divmod__(self, other) divmode() 返回值為元祖 (商值,余數(shù)) __lshift__(self, other) 左移:<< __rshift__(self, other) 右移:>> __and__(self, other) 按位與:& 注意以下均為按位操作,非邏輯操作 __or__(self, other) 按位或:| __xor__(self, other) 按位異或:^反運(yùn)算符方法
__radd__(self, other) 加法,如a+b,當(dāng)a不支持__add__()操作時(shí),調(diào)用此函數(shù); 即在運(yùn)算符的基礎(chǔ)上加上 'r' 即可,以下雷同 __rsub__(self, other) other - self增量賦值運(yùn)算方法
__iadd__(self, other) 賦值加法:+= 即在賦值運(yùn)算符之前加 'i' ,以下雷同 __isub__(self, other) 賦值減法:-= self = self - other一元運(yùn)算符方法
__pos__(self) 定義正號(hào):+x __neg__(self) 定義負(fù)號(hào):-x __abs__(self) 取絕對(duì)值 __invert__(self) 按位求反:~x比較運(yùn)算符方法
__gt__(self, other) 大于:> __ge__(self, other) 大于等于:>= __lt__(self, other) 小于:< __le__(self, other) 小于等于:<= __eq__(self, other) 相等:== __ne__(self, other) 不等:!=屬性操作
__getattr__(self, name) 當(dāng)用戶訪問一個(gè)不存在的屬性時(shí)調(diào)用 注意 object/super() (所有類的基類) 是無該方法的 __getattribute(self, name) 訪問存在的屬性時(shí)調(diào)用 先調(diào)用此函數(shù),如找不到該屬性,再去調(diào)用上面的屬性 __setattr__(self, name, value) 設(shè)置屬性時(shí)調(diào)用 __delattr__(self, name) 刪除一個(gè)屬性時(shí)調(diào)用 __get__(self, instance, owner) 描述符被訪問時(shí)調(diào)用 想詳細(xì)了解,請(qǐng)點(diǎn)擊這里__set__(self, instance, value) 描述符被改變時(shí)調(diào)用 __delelte__(self, instance, value) 刪除描述符時(shí)調(diào)用容器類型操作
__len__(self) 求容器的大小(注意與capacity的區(qū)別) 可變和非尅便容器均具備 __len__ 和 __getitem__ __getitem__(self, key) 獲取容器中指定元素的行為 __setitem__(self, key, value) 設(shè)置容器中指定元素的行為 只有可變?nèi)萜鲹碛?__setitem__ 和 __delitem__ __delitem__(self, key) 刪除容器中指定元素的行為 __iter__(self) 定義迭代器中元素的行為 __reversed__(self) 當(dāng)調(diào)用reversed()函數(shù)時(shí) __contains__(self, item) 成員運(yùn)算符in/ not in的行為PS:
- 以上所有的魔法方法,采用__xx__形式(__為雙 “_”,雙下劃線)
- 以上魔法方法為Python解釋器自動(dòng)調(diào)用,當(dāng)然也可以手動(dòng)調(diào)用
- 魔法方法Python解釋器自動(dòng)給出默認(rèn)的,因此除非需要改變其內(nèi)部功能,其它時(shí)刻刻使用默認(rèn)魔法方法
- 魔法方法是針對(duì)class而言的,脫離了”類“談magic_method是沒有意義的
- *argv為可變的參數(shù)列表,類似C語言的va(variable argument),注意與指針的區(qū)別,python中暫時(shí)忘掉指針,因?yàn)閜ython的內(nèi)存機(jī)制都是解釋器自動(dòng)完成的
反射(hasattr和getattr和setattr和delattr)
反射機(jī)制簡(jiǎn)介:
通過字符串的形式導(dǎo)入模塊
通過字符串的形式,去模塊中尋找指定的函數(shù),并執(zhí)行
規(guī)定用戶輸入格式 模塊名/函數(shù)名 通過__import__的形式導(dǎo)入模塊,并通過 hasattr和getattr 檢查并獲取函數(shù)返回值
反射的概念:
反射指的是通過 “字符串” 對(duì) 對(duì)象的屬性進(jìn)行操作。
- hasattr: 通過 “字符串” 判斷對(duì)象的屬性或方法是否存在 - hasattr(ogj,name_str) 判斷一個(gè)對(duì)象里是否有對(duì)應(yīng)的字符串方法 - 當(dāng)然對(duì)于python的對(duì)象而言,屬性包含變量和方法;有則返回True,沒有則返回False; - 需要注意的是name參數(shù)是string類型,所以不管是要判斷變量還是方法,其名稱都以字符串形式傳參; class Dog(object):def eat(self,food):print("eat method!!!") d = Dog()#hasattr判斷對(duì)象d是否有eat方法,有返回True,沒有返回False print(hasattr(d,'eat')) #True print(hasattr(d,'cat')) #False - getattr: 通過 “字符串” 獲取對(duì)象的屬性或方法 - getattr(obj,name_str) 根據(jù)字符串去獲取obj對(duì)象里的對(duì)應(yīng)的方法的內(nèi)存地址 - 獲取object對(duì)象的屬性的值,如果存在則返回屬性值,如果不存在分為兩種情況: - (1)沒有default參數(shù)時(shí),會(huì)直接報(bào)錯(cuò); - (2)給定了default參數(shù),若對(duì)象本身沒有name屬性,則會(huì)返回給定的default值; - 如果給定的屬性name是對(duì)象的方法,則返回的是函數(shù)對(duì)象,需要調(diào)用函數(shù)對(duì)象來獲得函數(shù)的返回 - 值; - 調(diào)用的話就是函數(shù)對(duì)象后面加括號(hào),如func之于func(); class Dog(object):def eat(self):print("eat method!!!") d = Dog()if hasattr(d,'eat'): # hasattr判斷實(shí)例是否有eat方法func = getattr(d, 'eat') # getattr獲取實(shí)例d的eat方法內(nèi)存地址func() # 執(zhí)行實(shí)例d的eat方法 #運(yùn)行結(jié)果: eat method!!! - setattr: 通過 “字符串” 設(shè)置對(duì)象的屬性或方法。 - 使用stattr給類實(shí)例對(duì)象動(dòng)態(tài)添加一個(gè)新的方法 - 給object對(duì)象的name屬性賦值value,如果對(duì)象原本存在給定的屬性name,則setattr會(huì)更改屬性的值為給定的value - 如果對(duì)象原本不存在屬性name,setattr會(huì)在對(duì)象中創(chuàng)建屬性,并賦值為給定的value; def abc(self):print("%s正在交談"%self.name)class Person(object):def __init__(self,name):self.name = namep = Person("星琿) setattr(p,"talk",abc) # 將abc函數(shù)添加到對(duì)象中p中,并命名為talk p.talk(p) # 調(diào)用talk方法,因?yàn)檫@是額外添加的方法,需手動(dòng)傳入對(duì)象# 打印結(jié)果 星琿正在交談setattr(p,"age",30) # 添加一個(gè)變量age,復(fù)制為30 print(p.age) - delattr: 通過 “字符串” 刪除對(duì)象的屬性或方法。 class Person(object):def __init__(self,name):self.name = namedef talk(self):print("%s正在交談"%self.name)p = Person("星琿)delattr(p,"name") # 刪除name變量 print(p.name)總結(jié)
以上是生活随笔為你收集整理的面向对象封装继承多态五大基本原则魔法方法反射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 装饰器,生成器,迭代器
- 下一篇: 列表字符串集合字典的常见方法