python中@property装饰器

Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情。在这篇文章中,我们将看到如何能做以下几点:

  • 将类方法转换为只读属性
  • 重新实现一个属性的setter和getter方法
@property
考察 Student 类:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
当我们想要修改一个 Student 的 scroe 属性时,可以这么写:

s = Student('Bob', 59)
s.score = 60
但是也可以这么写:

s.score = 1000
显然,直接给属性赋值无法检查分数的有效性。

如果利用两个方法:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
这样一来,s.set_score(1000) 就会报错。

这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。

但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。

有没有两全其美的方法?----有。

因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。

现在,就可以像使用属性一样设置score了:

>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score
说明对 score 赋值实际调用的是 set方法。

任务
如果没有定义set方法,就不能对“属性”赋值,这时,就可以创建一个只读“属性”。

通过上面的代码可以看出,@property 修饰函数score(getter),将score函数变成score属性输出,此外,@property 本身又创建了另一个装饰器@score.setter,负责把一个 setter 函数变成属性赋值,于是,我们虽然看到了类Student内部定义了两个函数score,对,没错,都是score,但是,他们却被不同的装饰器装饰,getter函数被@property修饰,setter函数被@property创建的函数的setter装饰器@score.setter修饰,因此,我们可以直接用s.score=90来代替s.set_socre(90),达到给score属性赋值的效果,简单粗暴,精益求精,虽然实现的效果一样,但是写起来,还是直接s.score=90来的更舒坦一些。从目的上讲,@property 修饰函数就是为了让调用者能用更少的代码去实现同样的功能。

拓展问题:

请给Student类加一个grade属性,根据 score 计算 A(>=80)、B、C(<60)。

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.__score = score
        self.__grade = None

    @property
    def score(self):
        return self.__score

    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

    # 请给Student类加一个grade属性,根据score 计算
    # A( >= 80)、B、C( < 60)。

    @property
    def grade(self):
        if self.score >= 80:
            self.__grade = "A"
        elif self.score >= 60:
            self.__grade = "B"
        else:
            self.__grade = "C"
        return self.__grade


s = Student('Bob', 59)
# print(s.grade)

s.score = 60
print(s.grade)
#
# s.score = 99
# print(s.grade)

分析:

    新添加的grade属性,是只读属性,可以只调用get方法,不调用set方法,来实现上述功能。

总结:

@property装饰器就是负责把一个方法变成属性调用,通常用在属性的get方法和set方法,通过设置@property可以实现实例成员变量的直接访问,又保留了参数的检查。另外通过设置get方法而不定义set方法可以实现成员变量的只读属性。

猜你喜欢

转载自blog.csdn.net/weixin_42499361/article/details/82153712