Python裝飾器之property()詳解

pythontab發表於2017-05-08

1. 何為裝飾器?

官方定義:裝飾器是一個很著名的設計模式,經常被用於有切面需求的場景,較為經典的有插入日誌、效能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函式中與函式功能本身無關的雷同程式碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的物件新增額外的功能。


Python中總共包括三個內建裝飾器:


① staticmethod

② classmethod

③ property


2. 屬性函式 property() 淺談


2.1 為什麼要使用 property?

通常,我們在訪問屬性和給屬性賦值的時候,都是對 類和例項 __dict__ 打交道的;但如果我們想要規範屬性訪問,有兩種方式可用:①資料描述符 ,②. property() 屬性函式。


然而,我們知道,描述符相對比較複雜,對於新手來說,用起來很吃力,那麼不妨試試property(),相對於描述符這個大的程式,property就相當於執行緒。


2.2 函式原型:

property(fget=None, fset=None, fdel=None, doc=None)

2.3 普通方法定義:

假設 calss Normal中有一個私有變數 __x,如下程式碼所示:

#code 1
class Normal:
    def __init__(self):
        self.__x = None
    def getx(self):
        return self.__x
    def setx(self, value):
        self.__x = value
    def delx(self):
        del self.__x
tN = Normal()
print(tN.__count)

輸出結果(報錯了)

Traceback (most recent call last):
  File "C:/Users/Administrator/AppData/Local/Programs/Python/Python35/property.py", line 15, in <module>
    print(tN.__count)
AttributeError: 'Normal' object has no attribute '__count'


為啥報錯了呢?因為 例項tN的屬性 __x 為私有屬性,不能直接訪問,為此我們只能呼叫內部定義的 方法;

tN = Normal()
tN.setx(10)
print(tN.getx())

輸出結果:

6 10


使用內部的方法,可以容易的得到例項的或者類的私有屬性值;


然而,如果我想把 class Normal 的 setx方法名改成了其它(如 Normal_setx),外部很多地方用到了該函式,是不是我需要一個一個的去找該方法的呼叫地點,然後一個一個的改呢?


c語言或許會,但Python,一個高階語言,怎麼會這麼點事都解決不了呢?

那麼,該如何解決以上問題呢?


其實有兩種方法。


方法一:使用 屬性函式property()

class Normal:
    def __init__(self):
        self.__x = None
    def getx(self):
        print('getx(): self.__x=', self.__x)
        return self.__x
    def setx(self, value):
        self.__x = value
        print('setx()')
    def delx(self):
        print('delx()')
        del self.__x
    y = property(getx, setx, delx, "I'm a property")
tN=Normal()
tN.y=10
tN.y
del tN.y
#輸出結果:
setx()
getx(): self.__x= 10
delx()

直接把方法當屬性來操作了,非常方便

方法二:使用 @property 裝飾器

class Normal:
    
    def __init__(self):
        self.__x = None
    @property
    def xx(self):
        print('getx(): self.__x=', self.__x)
        return self.__x
    
    @xx.setter
    def xx(self, value):
        self.__x = value
        print('setx()')
    @xx.deleter
    def xx(self):
        print('delx()')
        del self.__x
tN=Normal()
tN.xx=10
tN.xx
del tN.xx
#輸出結果資訊:
setx()
getx(): self.__x= 10
delx()

跟方法一 輸出同樣的結果,證明,這兩種方法都可行的(注意:第一個一定是 @property(替代getter哦,不然會報錯))。


相關文章