在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:
s = Student()
s.score = 9999
这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:
class Student():
def get_score(self):
return self._score
def set_score(self,value):
if not isinstance(value,int): #isinstance() 函数来判断一个对象是否是一个已知的类型
raise ValueError('score must be an integer')
if value < 0 and value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
>>s = Student()
>>s.set_score(60)
>>s.get_score()
60
>>s.set_score(99999)
ValueError: score must between 0 ~ 100!
但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。我们如果想直接把score绑定为Student的一个属性,方便来调用和赋值的话,就得这么修改:
class Student():
def __init__(self):
self._score = None
def get_score(self):
return self._score
def set_score(self, value):
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
score = property(get_score, set_score) # 将方法变为属性
if __name__ == "__main__":
s = Student()
>>s.score = 88
>>s.score
88
>>s.score = 999
ValueError: score must between 0 ~ 100!
其实我们还有另外一种更好的办法,就是把一个getter变为@property,而@property本身又创建了另一个装饰器,这里是@score.setter,这样getter、setter方法都变为属性可以赋值调用了
class Student():
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
>>s = Student()
>>s.score = 60
>>s.score
60
>>s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
这个程序里就不用特意写get_score和set_score了,@property已经分配好了,所以我们两个函数都可以叫score
这样我们就可以只通过s.score来方便地操作数据了,当然我们依旧不能取范围以外的值
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self,value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
最后我们再看@deleter,只要再写一个如下的函数,我们就可以通过del s.score来轻松删掉原来的值了
class Student():
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
@score.deleter
def score(self):
del self._score