類屬性和對象屬性--定義和作用域


類屬性和對象屬性定義

   Python一切皆對象(object),每個對象都可能有多個屬性(attribute)。Python的屬性有一套統一的管理方案。

   對象的屬性可能來自於其類定義,叫做類屬性(class attribute)。類屬性可能來自類定義自身,也可能根據類定義繼承來的。

   一個對象的屬性還可能是該對象實例定義的,叫做對象屬性(object attribute)。

   對象的屬性儲存在對象的__dict__屬性中。

   dir()返回的僅是對象的屬性的一個名字類表,而 __dict__ 返回的是一個字典,它的鍵(key)是屬性名,鍵值(value)是相應的屬性對象的數據值。


chicken類繼承自bird類,而>>> summer為chicken類的一個對象。

 

class bird(object):

    feather = True

class chicken(bird):

    fly = False

    def __init__(self, age):

        self.age = age

 

  

 

>>> summer = chicken(2)

>>> print(bird.__dict__)   類屬性

{'__dict__': <attribute '__dict__' of 'bird' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'bird' objects>, 'feather': True, '__doc__': None}

>>> print(chicken.__dict__) 類屬性

{'fly': False, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x2b91db476d70>}

>>> print(>>> summer.__dict__)  對象屬性

{'age': 2}

 

   當我們有一個>>> summer對象的時候,分別查詢>>> summer對象、chicken類、bird類以及object類的屬性,就可以知道>>> summer對象所有的__dict__,就可以找到通過對象>>> summer可以調用和修改的所有屬性了。下面兩種屬性修改方法等效:

 

>>> summer.__dict__['age'] = 3

>>> summer.age = 5


即時生成屬性

   同一個對象的不同屬性之間可能存在依賴關系。當某個屬性被修改時,我們希望依賴於該屬性的其他屬性也同時變化。這時,我們不能通過__dict__的方式來靜態的儲存屬性。Python提供了多種即時生成屬性的方法。其中一種稱為特性(property)。特性是特殊的屬性。比如我們為chicken類增加一個特性adult。當對象的age超過1時,adult為True;否則為False:


方案1 --> 稍顯麻煩

--------------------------------------------------------------------------------------

class chicken(bird):

    fly = False

    def __init__(self, age):

        self.age = age

    def getAdult(self):

        if self.age > 1.0: self.adult = True

        else: self.adult = False

--------------------------------------------------------------------------------------

獲得adult對象屬性的方法

>>> summer = chicken(2) #實例化

>>> summer.getAdult()   #調用getAdult()方法,給adult屬性賦值

>>> summer.adult        #獲取adult屬性

 


方案2 --> 使用三元選擇,實用性較低

--------------------------------------------------------------------------------------

class bird(object):

    feather = True

class chicken(bird):

    fly = False

    def __init__(self, age):

        self.age = age

        self.adult = True if self.age > 1.0 else False

--------------------------------------------------------------------------------------

獲得adult對象屬性的方法

>>> summer = chicken(2) #實例化

>>> summer.adult        #獲取adult屬性

 


方案3 使用property,實用性更強

--------------------------------------------------------------------------------------

class bird(object):

    feather = True

class chicken(bird):

    fly = False

    def __init__(self, age):

        self.age = age

    def getAdult(self):

        if self.age > 1.0: return True

        else: return False

    adult = property(getAdult)

--------------------------------------------------------------------------------------

獲得adult對象屬性的方法

>>> summer = chicken(2) #實例化

>>> summer.adult        #獲取adult屬性

 


????

class num(object):

    def __init__(self, value):

        self.value = value

    def getNeg(self):

        return -self.value

    def setNeg(self, value):

        self.value = -value

    def delNeg(self):

        print("value also deleted")

        del self.value

    neg = property(getNeg, setNeg, delNeg, "I'm negative")

x = num(1.1)

print(x.neg)

x.neg = -22

print(x.value)

print(num.neg.__doc__)

del x.neg

   上面的num為一個數字,而neg為一個特性,用來表示數字的負數。當一個數字確定的時候,它的負數總是確定的;而當我們修改一個數的負數時,它本身的值也應該變化。這兩點由getNeg和setNeg來實現。而delNeg表示的是,如果刪除特性neg,那么應該執行的操作是刪除屬性value。property()的最后一個參數("I'm negative")為特性negative的說明文檔。


方案4 使用特殊方法__getattr__

--------------------------------------------------------------------------------------

class bird(object):

    feather = True

class chicken(bird):

    fly = False

    def __init__(self, age):

        self.age = age

    def __getattr__(self, name):

        if name == 'adult':

            if self.age > 1.0: return True

            else: return False

        else: raise AttributeError(name)

--------------------------------------------------------------------------------------

   每個特性需要有自己的處理函數,而__getattr__可以將所有的即時生成屬性放在同一個函數中處理。__getattr__可以根據函數名區別處理不同的屬性。比如上面我們查詢屬性名male的時候,raise AttributeError。

   (Python中還有一個__getattribute__特殊方法,用於查詢任意屬性。__getattr__只能用來查詢不在__dict__系統中的屬性)

   __setattr__(self, name, value)和__delattr__(self, name)可用於修改和刪除屬性。它們的應用面更廣,可用於任意屬性。

 


即時生成屬性的其他方式

   即時生成屬性還可以使用其他的方式,比如descriptor(descriptor類實際上是property()函數的底層,property()實際上創建了一個該類的對象)。有興趣可以進一步查閱。

 


類屬性和對象屬性的作用域

類屬性:

    公有屬性,私有屬性,內置屬性

對象屬性:

公有屬性,私有屬性,內置屬性,方法變量,全局變量

    根據屬性不同,起作用范圍也不同。如下為圖示和說明:

--------------------------------------------------------------------------------------

class MyClass(object):

    """類公有屬性:在類中使用self.var1調用,類外使MyClass.var1調用, 

    也可以通過實例調用 instance.var1"""

    var1 = 'class public attr: var1'

    """類私有屬性:在類中使用self.__var2調用, 類外使用

    MyClass._MyClass__var2調用,也可以通過實例調用instance._MyClass__var2"""

    __var2 = 'class private attr: __var2'

 

    def method(self):

        """在方法method內有效"""

        var3 = 'method local attr: var3'

        print(var3)

        """對象公有屬性:方法調用后生效,在類內方法間通過self.var4調用,

        在類外通過instance.var4"""

        self.var4 = 'object public attr: self.var4'

        print(self.var4)

        """對象私有屬性:方法調用后生效, 在方法間內通過self.__var5調用,

        類內其他方法不可調用,在類外通過instance.__var5"""

        self.__var5 = 'object private attr: self.__var5'

        print(self.__var5)

 

    def method2(self):

        print(self.var1)

        print(self.__var2)

        print(self.var4)

--------------------------------------------------------------------------------------

"""通過類調用類屬性"""

>>> MyClass.var1

'class public attr: var1'

>>> MyClass._MyClass__var2

'class private attr: __var2'

"""通過對象調用類屬性"""

>>> obj = MyClass()

>>> obj.var1

'class public attr: var1'

>>> obj._MyClass__var2

'class private attr: __var2'

>>> obj.var4

'object public attr: self.var4'

>>> obj._MyClass__var5

'object private attr: self.__var5'

 


總結

   __dict__分層存儲屬性。每一層的__dict__只存儲該層新增的屬性。子類不需要重復存儲父類中的屬性。

   即時生成屬性是值得了解的概念。在Python開發中,你有可能使用這種方法來更合理的管理對象的屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM