標籤:參數 內建函數 資料 反射 報錯 UNC 機制 例子 lang
物件導向的特性一、封裝
Python不依賴語言的特性去封裝資料,而是通過遵循一定的資料屬性或函數屬性的命名來達到封裝的效果。任何以單底線開頭的名字都應該是內部的、私人的。封裝的意義在內部商務邏輯的資料隱藏。Python真正意義上的封裝是用類的內外訪問來區分的。並且它與Java的private屬性有很大的區別,Python並沒有強制性的拒絕外部類對私人屬性的訪問。換句話說,以單底線或雙底線開頭的私人屬性僅僅只是一種約定。需要注意的是,當我們使用另一個模組的私人屬性在匯入時,不能使用“*”號,只能使用私人屬性的名稱。Python有意義上的封裝層次。
1. 第一層封裝
使用以單底線開頭的私人屬性。對象在調用時可直接使用“對象名 . 私人屬性名稱”。
2. 第二層封裝
使用以雙底線開頭的私人屬性。對象在調用時不能直接使用“對象名 . 私人屬性名稱”。需要在雙底線開頭的私人屬性前加上“_類名”,如:“對象名 . _類名 . 私人屬性名稱”。
3. 四三層封裝
使用自訂的函數來提供介面。明確區分內外,實現內部商務邏輯的封裝,並像java的setter和getter方法一樣給出外部程式的使用自訂的介面函數,讓該介面函數返回一個值私人的性。但是在程式的設計中一定要清醒的認識到,程式在設計之初不應該被私人屬性所捆版,否則在今後的修改或維護中就會非常的痛苦。只有真正需要封裝的資料才需要封裝。比如員工的工資等重要的資料。
class Person: _privateproperty = "以單底線開頭的私人屬性" __property = "以雙底線開頭的私人屬性" def __init__(self, name, gender, age): self.name = name self.gender = gender self.age = age def return_property(self): return self.__property def showinfo(self): print(self.name, self.gender, self.age) person = Person("Handy","女",18) #單底線開頭的私人屬性 print(person._privateproperty) #雙底線開頭的私人屬性,注意調用方式 print(person._Person__property)
二、繼承
Python的繼承與C++的多繼承非常相似,它的繼承關係會被解譯器解釋為一個MRO列表,該MRO列表就是一個簡單的所有基類的線性順序列表。MRO列表的構造是通過一個C3線性化演算法來實現的。Python和java一樣,所有類的最終基類是Object。繼承從某種角度上來講是有害的,繼承將類與類之間耦合到一塊了。這大大的破壞了系統的封閉原則。繼承真正有意義的是介面式的繼承。Python提供的介面式的繼承。
Python 的繼承順序可由類使用__mro__查看。解譯器查看順序遵循以下三條規則:
1. 子類會先於父類被檢查
2. 多個父類會根據他們在列表中的順序進行檢查
3. 如果對下一個類存在兩個合法的選擇,選擇第一個父類
class Person: """ 描述人的類 """ def __init__(self, name, gender, age): self.name = name self.gender = gender self.age = age def printinfo(self): print("人類") class Student(Person): """ 學生的類 """ def __init__(self, name, gender, age, school): """ 使用super調用父類的建構函式時,參數中不能出現self,因為 super已經預設給出了self,如果此時加上self會報錯。而報錯 的原因是多了一個參數。使用super()調用父類的函數使程式更 加靈活。當然也可以使用以下耦合的調用模式。 Person.__init__(self, name, gender, age) """ super().__init__(name, gender, age) self.school = school def ptintinfo(self): print(self.name, self.gender, self.age, self.school) s = Student("Macky", "女", 18, "麻省理工") s.ptintinfo()
三、多態
Python的多態和java的多態一樣。多態的概念指出了對象如何通過他們共有的屬性及函數來訪問,不需要考慮他們之間的具體的類。
class Person: def __init__(self, name, age): self.name = name self.age = age def behavior(self): if self.age >= 0 and self.age <= 18: print("%s是未成年人"%self.name) else: print("%s是成年人"%self.name) class Adult(Person): pass class Pupil(Person): pass #實現多態的簡單例子 def func(obj): obj.behavior() #初始化Adult和Pupil adult = Adult("小明",3) pupil = Pupil("小華",20) #調用func函數 func(adult) func(pupil)
四、反射
反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和物件導向方面取得了成績。反射展示了某對象在運行期間是如何取得自己的狀態的。如果傳一個對象給你,你可以查出他的所有能力,這是一項強大的特性。如果Python不支援某種形式的反射功能,dir和type內建函數,將很難工作。還有那些特殊的屬性,像__dict__、__name__及__doc__。那反射究竟有什麼好處呢?它可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種“後期綁定”,你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能。這與Java的反射機制是一樣的,只不過在變現形式上不同。在開發中這項技術是必不可少的。
反射技術的實現基於以下四個函數:
hasattr(object, name)
判斷object中有沒有一個name字串對應的方法或屬性。
getattr(object, name, default=None)
擷取對象的屬性值或這函數的地址。當擷取對象的屬性值不存在時返回False,而函數不存在時報錯。如果要想函數不存在時不報錯能並且能通知我們函數不存在,惡可以使用default參數。該函數的功能與對象調用屬性相同。如:getattr(x, ‘y‘) <==> x.y
setattr(x, y, v)
為對象x的屬性y設定或修改一個值,當屬性不存在時,會將setattr設定的不存在的屬性向對象的字典中追加。如:setattr(x, y, v) <==> x.y =v
delattr(x, y)
刪除對象的屬性。如:delattr(x, y) <==> del x.y
class Person: def __init__(self, name, gender, age): self.name = name self.gender = gender self.age = age def eating(self): print("在吃飯") def sleep(self): print("在睡覺") person = Person("Handy","女",18) #使用hasattr判斷對象中是否存在屬性name print(hasattr(person, "name")) #輸出:True #使用getattr擷取對象的屬性值 print(getattr(person, "name")) #輸出:Handy #使用getattr擷取對象的函數地址 print(getattr(person, "eating"))#輸出:eatting()的地址 #運行函數 getattr(person, "eating")() #輸出:在吃飯 #使用getattr的default參數 print(getattr(person, "eatingfood", "函數不存在")) #輸出:函數不存在 #使用setattr修改一個值 setattr(person, "name", "Lily") print(person.__dict__) #向對象的字典追加一個不存在的值 setattr(person, "ID", "001") print(person.__dict__) #增加函數1 setattr(person, "func", lambda x : x+1) print(person.func) print(person.func(10)) #增加函數2 setattr(person, "func", lambda self : self.name+"是可以這樣做的") print(person.func) print(person.func(person)) #使用delattr刪除對象的屬性 delattr(person, "ID") print(person.__dict__)
Python的物件導向特性