logo

该视频仅会员有权观看

立即开通课程「Python 入门」权限。

¥
199
/ 年

在面向对象编程中,我们经常需要对对象的属性进行访问和修改,但是直接访问和修改对象的属性可能会导致一些问题,比如无法对参数进行检查,这样就可以随意修改对象的属性,比如下面的例子:

s = Student("James") s.score = 9999

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

class Student(object): def get_score(self): return self._score def set_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

这就是前面我们提到的 gettersetter 方法,现在对 Student 实例进行操作,就不能随意更改 score 了:

现在,对任意的 Student 实例进行操作,就不能随心所欲地设置 score 了:

s = Student() s.set_score(60) # ok! print(s.get_score()) # 60 s.set_score(999) # ValueError: score must between 0 ~ 100!

在 Python 当中我们有更简单的方式来实现上面的功能,那就是使用 @property 装饰器,该装饰器可以把一个方法变成属性调用:

class Student(object): @property def score(self): return self._score

我们只需要在一个 getter 方法上加上 @property 装饰器就可以把一个方法变成属性调用,比如上面的 score 方法,我们就可以通过 s.score 来获取 score 属性了,而不是通过 s.get_score() 方法,这样就可以更加方便地访问属性了。

另外当我们将方法变成属性调用后,@property 本身又会创建另一个装饰器 @score.setter,负责把一个 setter 方法变成属性赋值,这样我们就可以来定制 setter 方法了,比如下面的例子:

class Student(object): @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 方法转变成属性后,然后就可以通过 @score.setter 的装饰器来定义 setter 方法,这样我们就可以直接修改 score 属性了,而不是通过 s.set_score(60) 方法,这样就更加方便了。

s = Student() s.score = 60 print(s.score) # 60 s.score = 999 print(s.score) # ValueError: score must between 0 ~ 100!

如果我们只定义了 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 2014 - self._birth

上面类中 birth 是可读写属性,而 age 就是一个只读属性。

s = Student() s.birth = 1990 print(s.age) # 24 s.age = 25 # AttributeError: property 'age' of 'Student' object has no setter

@property 广泛应用在类的定义中,可以精简代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。