Python 中有三個專門用於裝飾類的方法的內置裝飾器:property()、classmethod()、staticmethod()。因爲這三個裝飾器是Python的內置的,所以,其內部的代碼是不可見,我們只能瞭解它們有什麼作用,被它們裝飾後的類的方法有什麼特殊之處。
一、類的屬性
@ property 裝飾過的類的方法,被稱爲類的屬性。方法變成屬性之後,最大的區別就是在引用時,不可以再傳遞參數,甚至連小括號也不能要了。例如:
class c01:
@property
def p01(self): return 100
obj01 = c01()
print(obj01.p01) # 100
print(obj01.p01()) # TypeError: 'int' object is not callable
使用屬性機制主要是爲了加強對對象的數據成員的保護。
對象數據成員如果是公開的和保護的,那麼就可以隨意地訪問、修改和刪除。如果是私有的,那麼就根本無法訪問。這兩種情況都比較極端:要麼隨意,要麼不可見。那能不能做到既可以訪問,又對修改和刪除進行一定的檢查和限制呢?能,屬性機制就是爲此而生。例如:
class c02:
def __init__(self,x=100):self.__v= x
@ property
def p01(self): return self.__v
obj02=c02()
print(obj02.p01) # 通過屬性可以訪問私有成員:100
print(obj02.__v) # 不能直接訪問私有成員:AttributeError: 'c02' object has no attribute '__v'
obj02.p01=200 # AttributeError: can't set attribute
del obj02.p01 # AttributeError: can't delete attribute
實際上,屬性主要就是用於間接地訪問和操作對象的私有數據成員。缺省情況下,屬性既不能被修改,也不能被刪除。不過,通過 property() 函數可以設置訪問、修改、刪除屬性時的魔法函數。
二、property() 函數
通過 property() 函數既可以定義一個屬性,同時還可以設置在訪問、修改、刪除這個屬性時的魔法函數。
屬性名 = property(訪問屬性時的魔法函數名, 修改屬性時的魔法函數名, 刪除屬性時的魔法函數名)
例如:
class c03:
def __p01get(self):print('Get p01')
def __p01set(self,x=1):print('Set p01')
def __p01del(self):print('del p01')
p01=property(__p01get,__p01set,__p01del) # 定義屬性 p01,同時設置操作它時的魔法函數
def __p02get(self):print('Get p02')
def __p02set(self,x=1):print('Set p02')
def __p02del(self):print('del p02')
p02=property(__p02get,__p02set,__p02del) # 定義屬性 p02,同時設置操作它時的魔法函數
obj03=c03()
obj03.p01 # 訪問屬性時系統自動調用 __p01get(): Get p01
obj03.p01=200 # 修改屬性時系統自動調用 __p01set(): Set p01
del obj03.p01 # 刪除屬性時系統自動調用 __p01del(): del p01
obj03.p02 # Get p02
obj03.p02=200 # Set p02
del obj03.p02 # del p02
三、通過屬性操作私有成員
class c04:
def __init__(self,x,y):self.__v1= x;self.__v2= y;
def __p01get(self):return self.__v1
def __p01set(self,x):
if x>=10: self.__v1=x; print('Set p01 OK:',self.__v1)
else: print('Set NO')
def __p01del(self):del self.__v1; print('p01 Del OK')
p01=property(__p01get,__p01set,__p01del) # 通過 p01 可操作私有數據成員 __v1
def __p02get(self):return self.__v2
def __p02set(self,x):
if x<10:self.__v2=x; print('Set p02 OK:',self.__v2)
else: print('Set NO')
def __p02del(self): print('p02 Can not Del')
p02=property(__p02get,__p02set,__p02del) # 通過 p02 可操作私有數據成員 __v2
obj04=c04(66,88)
print(obj04.p01) # 66
obj04.p01=5 # 不符合條件不允許修改:Set NO
obj04.p01=15 # 符合條件才允許修改:Set p01 OK: 15
del obj04.p01 # 實際刪除的是私有成員:p01 Del OK
print(obj04.p02) # 88
obj04.p02=5 # Set p02 OK: 5
obj04.p02=15 # Set NO
del obj04.p02 # 不允許刪除私有成員:p02 Can not Del