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