Python面向對象之類的成員

  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)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章