Python深入淺出property特性屬性

Pykk2019發表於2019-06-25

導語

在Java中,通常在類中定義的成員變數為私有變數,在類的例項中不能直接通過物件.屬性直接操作,而是要通過getter和setter來操作私有變數。
而在Python中,因為有property這個概念,所以不需要寫getter和setter一堆重複的程式碼來操作私有變數。Python“私有變數”通常在變數前加上“_”或者“__”,例如_attr或者__attr,這是約定俗成的規範。

把私有屬性變成只讀特性

class MyClass:

    def __init__(self, x):
        self._x = x

這裡定義了一個MyClass類,它有一個例項變數_x,繫結了使用者傳來的x值。_x是私有變數,通過obj._x獲取私有變數不符合語言規範,進而我們要使_x變成property(特性),通過obj.x直接訪問。

改造後的程式碼如下:

class MyClass:

    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        return self._x
    
>>> obj = MyClass(10)
>>> obj.x
10

我們把_x變成了property特性,以只讀的方式獲取x的值。

我們現在想為x賦值該怎樣做呢?

>>> obj.x = 999
Traceback (most recent call last):
  File "xxx", line 14, in <module>
    obj.x = 23
AttributeError: can't set attribute

可以看到,丟擲了AttributeError: can't set attribute。顯然,只讀方法不支援賦值。

把私有變數變成可賦值的特性

我們只需要在上述程式碼改造成:

class MyClass:

    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        return self._x
    
    @x.setter
    def x(self, value):
        self._x = value

>>> obj = MyClass(10)
>>> obj.x = 999
>>> obj.x
999

可以看到,我們為x新增了setter,可以直接為obj.x賦值操作

property屬效能夠遮蓋例項屬性

繼續上面的程式碼,我們看看以下的操作:

>>> obj = MyClass(10)
>>> obj.__dict__
{'_x': 999}  #此時例項變數中有_x的值
>>> obj.__dict__['x'] = 99999  #設定obj的例項變數有x值,跟property屬性重名!
>>> obj.__dict__
{'_x': 999, 'x': 99999}  #此時例項變數中有_x和x的值

>>> obj.x     #結果是obj的例項變數還是property屬性?
10

如上程式碼所示,obj物件有一個_x例項變數和一個x的property屬性,我們又強行為obj增加了一個x例項變數,這個例項變數x和property屬性x同名!
通過obj.x我們得知,返回的是property屬性,說明property屬性會遮蓋例項屬性!也可以理解為property屬性的優先順序更大!

property類解析

我們通常使用內建的@property裝飾器。但其實property是一個類,python中類和函式的呼叫方式都差不多,他們都是可呼叫物件
property的構造方法如下:

class property(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        """"""

它最大接受4個引數,都可以為空。
第一個為getter,第二個為setter,第三個為delete函式,第四個為文件。

上述程式碼的另一種寫法

class MyClass:

    def __init__(self, x):
        self._x = x

    def get_x(self):
        return self._x

    def set_x(self, value):
        self._x = value

    x = property(get_x, set_x)

>>> obj = MyClass(10)
>>> obj.x
10

如上,x是property的例項,設定了getter和setter,作為類變數放在MyClass類中。

以上就是property屬性的解析。

相關文章