Python面向對象的編程過程中,我們爲類實例化了對象,並通過對象指針來訪問類中對應的資源,那麼這些資源大體分爲三大部分,分別是字段、方法和屬性,我們將這三大塊統稱爲類的成員。
一、字段
字段可以分爲靜態字段、動態字段,下面通過代碼展示類中的兩種字段
class MyClass: # 靜態字段,屬於類,多個對象共用一個靜態字段 leader = "abuve" def __init__(self): # 動態字段,屬於對象,也可以叫普通的字段,每個對象都會有自己獨有的動態字段 self.name = "kevin"
動態字段在類的實例化過程中很常見,通過self爲每個對象封裝屬於自己特有的數據,但如果類中全部採用動態字段,也會遇到一些不合理的弊端,例如下面代碼:
class Company: def __init__(self, dept, leader): self.company_name = "Center" self.dept = dept self.leader = leader def ... if __name__ == "__main__": it_dept = Company("IT", "Abuve") hr_dept = Company("HR", "Kevin")
我們通過動態字段方式爲對象封裝了自己獨有的數據,但是這裏發現公司名稱company_name都爲“Center”,不管創建哪個部門的對象,公司名稱是不變的,我們知道動態字段存放在對象中,這樣每個對象就都包含了一份company_name字段,這無疑增加了程序對內存的開銷,因此更合理的方式應該使用靜態字段,代碼如下:
class Company: company_name = "Center" def __init__(self, dept, leader): self.dept = dept self.leader = leader def ... if __name__ == "__main__": it_dept = Company("IT", "Abuve") hr_dept = Company("HR", "Kevin")
同時在字段的調用方式上,我們也要遵循一些規則:
1、靜態字段,屬於類,通過類來調用訪問
2、動態字段,屬於對象,通過對象來調用訪問
對於上述代碼,我們通過下面的方式訪問其中的字段數據:
print it_dept.deptprint hr_dept.leaderprint Company.company_name
如果通過對象訪問靜態字段同樣可以訪問到數據,因爲對象也是通過對象指針指向了自己的類,對象中沒有的數據最終也會去類中查找,但是這樣的調用方式並不合理。
# 通過對象調用,同樣訪問到了類的靜態字段 print it_dept.company_name
在字段前加入兩個下劃線,可以將該字段設置爲私有字段,例如:
class MyClass: def __init__(self, name): self.__name = name def show(self): print self.__name if __name__ == "__main__": object = MyClass("Abuve") # 通過對象無法訪問到私有字段 print object.__name # 私有字段通過類的內部方法訪問 object.show() # 通過類名前加入下劃線的方式同樣可以訪問到 print object._MyClass__name
最後一種方式通過類名前加入下劃線的方式同樣訪問到了私有字段,但多數情況下儘量不要用這種方式進行訪問。
二、方法
在Python面向對象編程中,方法的調用最爲常見,分爲動態方法(普通方法)、靜態方法、類方法,下面通過代碼展示。
class MyClass: def __init__(self, name): self.name = name # 普通方法 def show(self): return self.name # 靜態方法 @staticmethod def detail(name): print '%s is good person.' %name # 動態方法 @classmethod def show_detail(cls): cls.detail('Kevin') if __name__ == "__main__": object = MyClass("Jack") p_name = object.show() MyClass.detail(p_name) MyClass.show_detail()
與字段一樣,方法的調用上依然要遵循一些規則。
1、普通方法,由對象調用
2、靜態方法,由類調用
3、類方法,屬於靜態方法的一種,通過類來調用,執行的時候會自動將類名傳遞進去,因此要有一個默認的接收參數。
靜態方法依然也可以通過對象指針來訪問到,但是這樣調用並不合理,之所以將這種稍微特殊的方法寫到類中,也是因爲其與該類具備一定的相關性。
三、屬性
如果說字段屬於左派、方法屬於右派,那麼屬性就屬於中立派,因爲它即具備方法的功能,同時又可以通過字段的方式來訪問,下面爲一段包含屬性的代碼段。
class PageSet: def __init__(self, count, page_size): self.count = count self.page_size = page_size # 通過裝飾器將page_num變爲屬性,對象調用時不需要再加括號 @property def page_num(self): page_count, remainder = divmod(self.count, self.page_size) if remainder == 0: return page_count else: return page_count + 1 if __name__ == "__main__": # 傳入條目總數,以及單頁size大小 page_tools = PageSet(108, 10) # 像訪問字段一樣執行了page_num方法 print page_tools.page_num
上面的代碼實現了一個分頁設置,我們通過裝飾器property將page_num方法變爲屬性,那麼該方法在被對象調用時,就像訪問字段一樣,不需要再加括號了。此時我們只實現了通過字段的方式來訪問方法,通過下面的代碼,我們也可以爲屬性調用相關的賦值、刪除動作。
class PageSet: def __init__(self, count, page_size): self.count = count self.page_size = page_size @property def page_num(self): page_count, remainder = divmod(self.count, self.page_size) if remainder == 0: return page_count else: return page_count + 1 @page_num.setter def page_num(self, value): print value print 'This is set function.' @page_num.deleter def page_num(self): print 'This is delete function.' if __name__ == "__main__": page_tools = PageSet(108, 10) # 調用property修飾屬性 page_tools.page_num # 調用page_num.setter修飾屬性 page_tools.page_num = 12 # 調用page_num.deleter修飾屬性 del page_tools.page_num
四、特殊成員
特殊成員指函數兩邊都帶有下劃線的特殊方法,這些特殊方法爲類提供獨有的功能。
1、__init__
構造方法,這類方法最爲常見,在我們實例化類的時候,就是通過__init__構造方法封裝了對象的數據。
2、 __del__
析構函數,通過__del__函數構造特定功能,在爲對象執行del操作時,可以自動調用該部分代碼,在程序執行相關垃圾回收時,可以應用析構方法。
3、__doc__
註釋,通過對象,可以訪問到__doc__函數中指定的註釋內容。
4、__module__
通過該方法可以顯示當前對象屬於哪個模塊。
5、__class__
通過該方法可以顯示當前對象屬於哪個類。
6、__call__
如果我們在類的實例化對象後面加括號時,會自動執行類中的call方法。
class MyClass: def __call__(self): print 'This is something...' if __name__ == "__main__": object = MyClass() object()
7、__str__
默認打印對象時,只能夠顯示內存地址,通過__str__可以顯示想要返回的內容。
class MyClass: def __str__(self): return 'This is text that I want to return...' if __name__ == "__main__": object = MyClass() print object
8、__add__
可以將兩個對象中的內容進行相加。
class MyClass: def __init__(self, company, ceo): self.company = company self.ceo = ceo def __add__(self, other): return "%s---%s" %(self.company, other.ceo) obj1 = MyClass("A","Abuve") obj2 = MyClass("B", "Kevin") print obj1 + obj2
代碼最終打印了 "A---Kevin"
9、__dict__
對象調用該方法,可以打印出所有封裝的數據,類調用該訪問可以打印出所有方法。
10、__getitem__、__setitem__、__delitem__
通過字典的方式操作對象,可以爲其設置相應的執行動作。
class MyClass(object): def __getitem__(self, key): print '__getitem__',key def __setitem__(self, key, value): print '__setitem__',key,value def __delitem__(self, key): print '__delitem__',key if __name__ == "__main__": obj = Myclass() result = obj['k1'] # 執行了__getitem__方法 obj['k2'] = 'abuve' # 執行了__setitem__方法 del obj['k1'] # 執行了__delitem__方法
11、__iter__
用於迭代器,返回一個可以被迭代的對象
class MyClass(object): def __iter__(self): return iter([1,2,3,4,5]) if __name__ == "__main__": obj = MyClass() for i in obj: print i
12、isinstance/issubclass
通過isinstance可以判斷某個對象的類型,issubclass可以判斷某兩個類是否爲繼承關係
class Class1(): pass class Class2(Class1): pass if __name__ == "__main__": obj = Class2() # 判斷obj的類型是否爲Class2 print isinstance(obj, Class2) # isinstance同樣也可以判斷是否繼承自父類 print isinstance(obj, Class1) print issubclass(Class2, Class1)