上一次寫過一篇有關於python類的部落格,現在回頭去看看,發現好多文法還是比較低級,表達不是很清晰。現在談一談對python類的表達的新的理解。
本篇部落格的重點是向大家介紹一些與類定義相關的常見的編程模式,主要包括讓對象支援常見的python特性、特殊方法的使用,封裝、繼承,記憶體管理、以及一些有用的設計模式。 1 修改執行個體的字串表示
在python類的定義的時候,我們可以通過定義__repr¬¬__()方法和__str__()方法來實現執行個體的字串輸出
1.1 特殊方法repr()返回的是執行個體的代碼錶示,也就是能通過他返回的字串文本來重新建立這個執行個體,即滿足obj = eval(repr(obj))。 但是如果不能做到這個條件,最好也能夠讓他產生一段具有協助意義的文本,並且以< 文檔 >的形式表達。
1.2 str()方法就比較好理解,它是將執行個體轉換為字串,用做print輸出,也就是你想print()輸出什麼就在str()中定義什麼就好。
class Point: def __init__(self,x,y): self.x = x self.y = y def __repr__(self): return 'point({0.x!r},{0.y!r})'.format(self) def __str__(self): return '({0.x!s},{0.y!s})'.format(self)aOut[3]: point(3,4)print(a)(3,4)
從這個例子中我們就可以看出兩者的區別。特別注意的是:(1)。r是repr()專用,一般不用在str()中(2)關於format()格式化輸出會專門寫一篇部落格來介紹,其作用還是非常強大的。(3)0代表的是self. 0.x也就是self.x 和super()類似。 2 自訂字串的輸出格式
利用format()函數和字串方法可以實現讓對象支援自訂的輸出格式,只需要在類的定義中添加format()方法。
_formats = { 'ymd': '{d.year}-{d.mouth}-{d.day}', 'mdy': '{d.mouth}/{d.day}/{d.year}', 'dmy': '{d.day}/{d.mouth}/{d.year}' }class Date: def __init__(self,year,mouth,day): self.year = year self.mouth = mouth self.day = day def __format__(self,code): if code == '': code = 'ymd' fmt = _formats[code] return fmt.format(d=self)a = Date(2013,3,5)print(format(a))print(format(a,'mdy'))print(format(a,'dmy'))
format()方法在python字串格式化功能中提供了一個鉤子,對于格式化輸出的的內容完全取決於類本身,也就是編程人員自訂。一般來說格式化代碼可以為任何形式。 3 讓對象支援上下文管理協議
Python中對象能夠支援上下文管理協議(context_management protocol),它是通過with語句觸發運行,也就是在進入with語句時候建立對象,在退出with語句的時候銷毀改對象。
Python中是在類的定義中使用enter()方法和exit()方法實現這個功能。
#-----------------------------------------------------------# 這裡有一個例子 |#-----------------------------------------------------------
4 用slot方法節約記憶體
針對於用作簡單資料結構的類,通常可以添加slot()方法來減少其對記憶體的使用。當定義了slot()方法時,python就會針對執行個體採用一種更加緊湊的內部結構表示,不再讓每個執行個體都建立一個dict字典。使用slot()方法的缺點就是無法再為執行個體添加新的屬性,只能使用在定義的時候就寫下的屬性。
slot()方法一般被視作python的最佳化方法,當然有時候也用來約束程式,阻止使用者為執行個體添加新的屬性。
#-----------------------------------------------------------# 這裡有一個例子 |#-----------------------------------------------------------
5 python類的封裝
“封裝”就是將抽象得到的資料和行為(或功能)相結合,形成一個有機的整體(即類);封裝的目的是增強安全性和簡化編程,使用者不必瞭解具體的實現細節,而只是要通過外部介面,特定的存取權限來使用類的成員。
與其他以來語言特性來封裝類的程式設計語言不同的是python通過特定的命名規則來表達對資料和方法的用途。(1)任何以雙底線(__)開頭的名字屬於私人屬性或者方法,只能在該類中被調用,不用在外部調用或者繼承。同時這個規則也適用於塊的定義和模組中函數的定義。
class A: def __init__(self): self.__private = 0 #私人屬性 self.public = 0 #公有屬性 def public_method(self): #公有方法 ''' :return: ''' print('This is a public method') def __private_method(self): #私人方法 ''' :return: ''' print('This is a private method')a = A()a.public_method()a.__private_method() #會報錯print(a.__private) #會報錯Traceback (most recent call last): File "D:/home/WX/test_clsaa.py", line 45, in <module> a.__private_method()AttributeError: 'A' object has no attribute '__private_method'
但如果一定要訪問私人屬性也是可以的。使用: 執行個體名._類名私人屬性名稱(例如: a._A__private )就可以訪問。
class A: def __init__(self): self.__private = 0 #私人屬性 self.public = 0 #公有屬性 def public_method(self): #公有方法 ''' :return: ''' print('This is a public method') def __private_method(self): #私人方法 ''' :return: ''' print('This is a private method')a = A()print(a._A__private)a._A__private_method()0This is a private method
同樣,私人屬性和方法不能被子類繼承,也不會被子類覆蓋。