Python装饰器之property
我们一直在用“类对象.属性”的方式访问类中定义的属性,其实这种做法是欠妥的,因为它破坏了类的封装原则。正常情况下,类包含的属性应该是隐藏的,只允许通过类提供的方法来间接实现对类属性的访问和操作。
操作类属性
在不破坏类封装原则的基础上,为了能够有效操作类中的属性,类中应包含读(或写)类属性的多个 getter(或 setter)方法,这样就可以通过“类对象.方法(参数)”的方式操作属性
class Student:
def __init__(self, name):
self.name = name
def set_name(self, name):
self.name = name
def get_name(self):
return self.name
def del_name(self):
self.name = "xxx"
student = Student("Python")
print(student.get_name())
student.set_name("Java")
print(student.get_name())
student.del_name()
print(student.get_name())
### 运行结果
Python
Java
xxx
property() 函数
上面这种操作类属性的方式比较麻烦,我们更习惯于使用“类对象.属性”这种方式,Python 中提供了 property() 函数,可以实现在不破坏类封装原则的前提下,让开发者依旧使用“类对象.属性”的方式操作类中的属性。
property() 函数的基本使用格式如下:
属性名 = property(fget=None, fset=None, fdel=None, doc=None)
在使用 property() 函数时,以上 4 个参数可以仅指定第 1 个、或者前 2 个、或者前 3 个,当前也可以全部指定。也就是说,property() 函数中参数的指定并不是完全随意的。
想要有写和删的权限必须要有读的权限,否则报错
name = property(getname) # name 属性可读,不可写,也不能删除
name = property(getname, setname) # name属性有读、写的权限,但是不能删除
name = property(getname, setname,delname) #name属性可读、可写、也可删除,就是没有说明文档
class Students:
def __init__(self, name):
self.__name = name
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def del_name(self):
self.__name = "xxx"
# 为name 属性配置 property() 函数
name = property(get_name, set_name, del_name, '指明出处')
# 调取说明文档的 2 种方式
print(Students.name.__doc__)
help(Students.name)
student = Students("C语言")
print(student.name)
student.name = "Python教程"
print(student.name)
del student.name
print(student.name)
### 运行结果
指明出处
Help on property:
指明出处
C语言
Python教程
xxx
注意,在此程序中,由于 getname() 方法中需要返回 name 属性,如果使用 self.name 的话,其本身又被调用 getname(),这将会先入无限死循环。为了避免这种情况的出现,程序中的 name 属性必须设置为私有属性,即使用 __name(前面有 2 个下划线)。
property装饰器用法
class Rect:
def __init__(self, area):
self.__area = area
@property # 只读权限
def area(self):
return self.__area
@area.setter # 拥有读写权限,前提是上面一定有property(要用只读),否则报错
def area(self, value):
self.__area = value
@area.deleter # 拥有删除权限,前提是上面一定有property(要用只读),否则报错
def area(self):
del self.__area
rect = Rect(30)
print("初始化的area值是:", rect.area)
rect.area = 90
print("修改后的area值是:", rect.area)
del rect.area
print("删除后的area值是:", rect.area)
### 运行结果:
初始化的area值是: 30
修改后的area值是: 90
Traceback (most recent call last):
File "tests.py", line 60, in <module>
print("删除后的area值是:", rect.area)
File "tests.py", line 44, in area
return self.__area
AttributeError: 'Rect' object has no attribute '_Rect__area'