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