Python中的property, setter裝飾器
阿新 • • 發佈:2019-02-17
1. 問題提出
python中用”.”操作來訪問和改寫類的屬性成員時,會呼叫__get__
和__set__
方法,模式情況下,python會查詢class.__dict__
字典,對對應值進行操作。比如C.x
會呼叫C.__get__
訪問最終讀取C.__dict__[x]
元素。
如果需要讀取時對輸出結果進行修飾或者對輸入進行合法化檢查,通常做法是自己寫get和set函式,並通過調get和set函式進行讀寫類成員屬性。
例子:
class Timer:
def __init__(self, value = 0.0):
self.time = value
self.unit = 's'
def get_time(self):
return str(self.time) + ' ' + self.unit
def set_time(self, value):
if(value < 0):
raise ValueError('Time cannot be negetive.')
self.time = value
t = Timer()
t.set_time(1.0)
t.get_time()
但是這樣並不美觀,那有沒有美顏的辦法呢?當然!
2. 解決方案
在變數x
前面加下劃線_
表示為私有變數_x
,並將變數名x
設為用property
property函式的宣告為
def property(fget = None, fset = None, fdel = None, doc = None) -> <property object>
其中fget
, fset
, fdel
對應變數操作的讀取(get),設定(set)和刪除(del)函式。
而property
物件<property object>
有三個類方法,即setter
, getter
和delete
,用於之後設定相應的函式。
3.實現效果
在操作類私成員的時候呼叫__get__
和__set__
property
中fget
和fset
指定的方法,從而實現了方便的賦值操作。 注意,即使在
__init__
函式中呼叫賦值語句,也使用的是fset
方法。
例子:
class Timer:
def __init__(self, value = 0.0):
# 1. 將變數加"_",標誌這是私有成員
self._time = value
self._unit = 's'
def get_time(self):
return str(self._time) + ' ' + self._unit
def set_time(self, value):
if(value < 0):
raise ValueError('Time cannot be negetive.')
self._time = value
# 將變數名賦值為包含get和set方法的property物件
time = property(get_time, set_time)
t = Timer()
t.time = 1.0
print(t.time)
這樣的訪問和設定和賦值語句一樣非常自然了。
上面的例子中,如果採用property物件的方法而不是用property函式,那麼
# time = property(get_time, set_time)
# =========將變成==============>>>
time = property()
time = time.getter(get_time)
time = time.setter(set_time)
4. property裝飾器
如果覺得在最後加property
函式這樣寫類的時候還是不自然,容易忘會寫錯,那麼裝飾器可以讓類的書寫帥到飛起。
例子:
class Timer:
def __init__(self, value = 0.0):
self._time = value
self._unit = 's'
# 使用裝飾器的時候,需要注意:
# 1. 裝飾器名,函式名需要一直
# 2. property需要先宣告,再寫setter,順序不能倒過來
@property
def time(self):
return str(self._time) + ' ' + self._unit
@time.setter
def time(self, value):
if(value < 0):
raise ValueError('Time cannot be negetive.')
self._time = value
t = Timer()
t.time = 1.0
print(t.time)
這兩個裝飾器
@property
裝飾器會把成員函式x
轉換為getter
,相當於做了x = property(); x = x.getter(x_get)
@x.setter
裝飾器會把成員函式x
轉換為setter
,相當於做了x = x.seter(x_set)
.
可以看到我們實現了通過屬性x
來對私有變數_x
進行操作。