python屬性property

屬性函數(property)
在對象中兩個很重要的元素就是屬性和方法,在調用的時候兩者是有區別的。

 class People:
     def __init__(self,first_name,last_name):
         self.first_name = first_name
         self.last_name  = last_name

     def get_first_name(self):
         return self.first_name

a = People('lala','ouyang')
print(a.get_first_name())
print(a.first_name)

從例子中我們可以發現,一樣的結果,但是調用的過程不一樣(雖然其實也就是多一個括號而已),那么有沒有一種辦法,使得我們調用屬性的時候就會自動調用相應的方法,也就是增加一些額外的處理過程(例如類型檢查或者驗證)。這時候屬性函數(@property)就能給我們提供很好的解決方案。

首先是最簡單的例子,自動調用get,set函數對屬性的處理。

class People:
    def __init__(self,name):
        self.name = name

    #getter function
    @property #屬性函數
    def name(self):
        return self._name

    #setter function
    @name.setter
    def name(self,name):
        self._name = name


a = People('leida')
print(a.name) 
a.name = 'libai' 
print(a.name)

正如例子中這樣。要定義對屬性的訪問,一種最簡單的方法就是將其定義為property。比如說,增加對屬性的類型檢查:

class People:
    def __init__(self,name):
        self.name = name

    #getter function
    @property #屬性函數
    def name(self):
        return self._name

    #setter function
    @name.setter
    def name(self,name):
        if not isinstance(name,str):
            raise TypeError('name must is string type')
        self._name = name

a = People(12)

當我們實現一個property時,底層數據仍然需要保存在某個地方,因而在get和set的方法中,可以看到直接對_name操作的,這就是數據實際保存的地方。但是,也發現在init()方法中任然是對self.name操作的。但是實際情況是我初始化的時候程序仍舊是對self._name操作的。(這點我也還不理解,應該不是這樣的啊.但是必須這么寫,不然會報錯)。
對于已經存在的get,set方法,同樣也可以定義為property:

class People:
    def __init__(self,name):
        self.name = name

    def get_name(self):
        print('calling the get function')
        return self._name

    def set_name(self,name):
        print('calling the set function')
        self._name = name

    name = property(get_name,set_name,del_name)

a = People('libai')

同時,在set_name 函數中做了打印標記,發現在init()方法中確實調用了set_name()函數。

Property屬性實際上就是把一系列的方法綁定到一起。如果檢查類的property屬性,就會發現property自身所持有的屬性fget,fset所代表的原始方法。

print(People.name.fget)
print(People.name.fset)

一般來說,我們不會直接去調用fset或者fget,但是當我們調用property屬性時會自動觸發對這些方法的調用。
上面例子中的兩種寫法,一般傾向于第二種寫法,特別是如果需要對某個普通的屬性額外增加處理步驟時,可以在不修改已有代碼的情況下將這個屬性提升為一個property。
Property也可以用來定義需要計算的屬性,這類屬性并不會實際被保存起來,而是根據需要完成計算。

import math
class Circle:
    def __init__(self,radius):
        self.radius = radius

    @property
    def area(self):
        return math.pi * self.radius**2
    @property
    def perimeter(self):
        return 2*math.pi*self.radius

c = Circle(5)
print(c.area)
print(c.perimeter)

這樣的寫法就會使得實例的接口變得統一,本來用方法實現的計算調用的時候用屬性就可以,很好的避免了方法、屬性傻傻分不清的情況了。
個人建議,不要在代碼中不斷重復使用@property,這樣會使得代碼變得臃腫,而且難以閱讀,容易出錯。同樣的任務,利用描述符或者閉包也能夠很好的完成。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,869評論 18 139
  • 函數和對象 1、函數 1.1 函數概述 函數對于任何一門語言來說都是核心的概念。通過函數可以封裝任意多條語句,而且...
    道無虛閱讀 4,630評論 0 5
  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,762評論 0 9
  • 人們好多都說那個人怎么怎么怎么,她又得獎了,他拿了獎學金,他的這個月的工資好高,經理又表揚他了,等等!可是這關你什...
    耳語心聲閱讀 995評論 0 1
  • 當今的人們壓力太大,對年輕人來說:獨身的時候忙于找對象,焦慮不安,沒法放松;成家以后,要買房買車、生兒...
    晚起畫蛾眉閱讀 1,742評論 3 2