在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

    1. s = Student()
    2. s.score = 9999

    这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:

    1. class Student():
    2. def get_score(self):
    3. return self._score
    4. def set_score(self,value):
    5. if not isinstance(value,int): #isinstance() 函数来判断一个对象是否是一个已知的类型
    6. raise ValueError('score must be an integer')
    7. if value < 0 and value > 100:
    8. raise ValueError('score must between 0 ~ 100!')
    9. self._score = value
    10. >>s = Student()
    11. >>s.set_score(60)
    12. >>s.get_score()
    13. 60
    14. >>s.set_score(99999)
    15. ValueError: score must between 0 ~ 100!

    但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。我们如果想直接把score绑定为Student的一个属性,方便来调用和赋值的话,就得这么修改:

    1. class Student():
    2. def __init__(self):
    3. self._score = None
    4. def get_score(self):
    5. return self._score
    6. def set_score(self, value):
    7. if value < 0 or value > 100:
    8. raise ValueError('score must between 0 ~ 100!')
    9. self._score = value
    10. score = property(get_score, set_score) # 将方法变为属性
    11. if __name__ == "__main__":
    12. s = Student()
    13. >>s.score = 88
    14. >>s.score
    15. 88
    16. >>s.score = 999
    17. ValueError: score must between 0 ~ 100!

    其实我们还有另外一种更好的办法,就是把一个getter变为@property,而@property本身又创建了另一个装饰器,这里是@score.setter,这样getter、setter方法都变为属性可以赋值调用了

    1. class Student():
    2. @property
    3. def score(self):
    4. return self._score
    5. @score.setter
    6. def score(self,value):
    7. if not isinstance(value, int):
    8. raise ValueError('score must be an integer!')
    9. if value < 0 or value > 100:
    10. raise ValueError('score must between 0 ~ 100!')
    11. self._score = value
    1. >>s = Student()
    2. >>s.score = 60
    3. >>s.score
    4. 60
    5. >>s.score = 9999
    6. Traceback (most recent call last):
    7. ...
    8. ValueError: score must between 0 ~ 100!

    这个程序里就不用特意写get_score和set_score了,@property已经分配好了,所以我们两个函数都可以叫score
    这样我们就可以只通过s.score来方便地操作数据了,当然我们依旧不能取范围以外的值

    还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:

    1. class Student(object):
    2. @property
    3. def birth(self):
    4. return self._birth
    5. @birth.setter
    6. def birth(self,value):
    7. self._birth = value
    8. @property
    9. def age(self):
    10. return 2015 - self._birth

    最后我们再看@deleter,只要再写一个如下的函数,我们就可以通过del s.score来轻松删掉原来的值了

    1. class Student():
    2. @property
    3. def score(self):
    4. return self._score
    5. @score.setter
    6. def score(self,value):
    7. if not isinstance(value, int):
    8. raise ValueError('score must be an integer!')
    9. if value < 0 or value > 100:
    10. raise ValueError('score must between 0 ~ 100!')
    11. self._score = value
    12. @score.deleter
    13. def score(self):
    14. del self._score