在装饰器详解中介绍了装饰器的基本用法,而python语言中内置了一些装饰器,本文介绍在类的方法定义中常用的装饰器: @property
。property本质上是装饰器类,顾名思义用于属性的提取,其可将方法装饰成属性。
下面为一个用@property
进行装饰的典型例子,实例方法name()
在装饰后可直接通过.name
进行调用(或者更严格的说法:属性取值)。property类除了提供了__get__
方法(即@property的底层函数),还提供了__set__
和__del__
函数,因此可以通过同名函数的fun.setter
和fun.deleter
分别进行属性的重新赋值和属性的删除。
class Student(object):
def __init__(self, name, age):
self._name = name # 这里也可写成self.name=name
self._age = age # 这里也可写成self.age = age
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@name.deleter
def name(self, name):
del self._name
if __name__ == '__main__':
s1 = Student('Mia', 18)
print(s1.name) # Mia
print(s1._name) # Mia
s1.name = 'Lee'
print(s1.name) # Lee
在利用@property
进行方法装饰时,要特别留意一种错误:递归调用陷阱
如在下面的例子里,其唯一的区别为在setter
中定义的为self.name=name
,而非成员变量self._name
,此时会循环调用装饰后对应的name
对象,从而导致错误。
class Student(object):
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self.name = name
if __name__ == '__main__':
s1 = Student('Mia', 18)
print(s1.name) # Mia
print(s1._name) # Mia
s1.name = 'Lee' # RecursionError: maximum recursion depth exceeded
print(s1.name)
直观上看,采用@property
装饰器对函数进行装饰有如下好处:
(1)将函数属性化;
(2)隐藏内部变量名称,从而保护代码;
(3)实现了对统一变量取值(get)、赋值(set)和删除(delete)的统一化。
除此之外,@property
装饰器最大的意义在于其对于多态的支持,即相同接口下不同的类,有的直接用变量实现,有的可以间接计算出来,有的可以在赋值时增加额外的动作等等,但通过@property
可以对外提供一致的接口。
【Reference】