在实际面向对象编程的过程中,实例对象的属性通常都有一定的存储逻辑。例如,学校管理系统中,学生的信息管理。我们需要记录学生的姓名,年龄,各科的成绩。然后还要根据各科的来判断该学生是否能够正常毕业。定义一个学生类可以这样:
class Student(object):
def __init__(self,name,age,grades):
self.name = name
self.age =age
self.grades =grades
def graduate(self):
if self.grades >= 60:
print("允许毕业")
else:
print("留级查看")
但这样似乎不是很合理,因为像年龄,学习成绩这些应该都是正整数,当我们录入这些信息的时候可能会出错。为了防止这种情况的发生,我们必须对age和grades进行限制。
最常用的就是get()和set()方法
1 不能通过"."直接访问属性,需要将属性私有化,python中的做法是在属性前加双下划线
2 提供get()和set()方法,以限制存储规则
如下:
class Student(object):
def __init__(self,name,age,grades):
self.__name = name
self.__age =age
self.__grades =grades
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self, age):
if isinstance(age,int) and age > 0:
self.__age = age
def get_grades(self):
return self.__grades
def set_grades(self, grades):
if isinstance(grades,int) and grades > 0:
self.__grades = grades
def graduate(self):
if self.grades >= 60:
print("允许毕业")
else:
print("留级查看")
这样写我们就age和grades存储的合理性 ,但也存在一些弊端:
- 我们不能通过“.”来访问属性
- 我们每一个属性都要写set和get方法,比较费劲
- 如果需要添加新的属性,还需要添加set和get方法
- 当我们要修改某个属性的时候,寻找对应的set和get方法比较费时间
通过property装饰器管理属性
class Student(object):
def __init__(self,name,age,grades):
self.name = name
self.age =age # 调用age.setter方法
self.grades =grades
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name = name
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if isinstance(age,int) and age > 0:
self.__age = age
else:
raise ValueError("数值输入异常")
@property
def grades(self):
return self.__grades
@grades.setter
def grades(self, grades):
if isinstance(grades,int) and grades > 0:
self.__grades = grades
else:
raise ValueError("数值输入异常")
def graduate(self):
if self.grades >= 60:
print("允许毕业")
else:
print("留级查看")
s = Student("jack",22,88)
s.grades = 33
print(s.grades)
- 函数在使用@property 装饰器装饰后,会变成类属性,而且会有一个 setter 方法,装饰同属性的 set 函数。被装饰的函数必须与属性(被@property 装饰器装饰的函数)同名
- 在给属性赋值的时候,执行的是setter函数。例如__init__方法中的self.age = age 执行的是装饰器@age.setter装饰的函数
- 访问属性的时候,执行的是装饰器@property装饰的函数,例如访问self.age 执行的是装饰器@property装饰的age()函数
- @property装饰的函数age返回的是self.__age而不是self.age,如果返回self.age 相当于执行了通过@property装饰的函数age,这会导致无限递归