zoukankan      html  css  js  c++  java
  • Python 利用@property装饰器和property()方法将一个方法变成属性调用

    在创建实例属性时,如果直接把实例属性暴露出去,虽然写起来简单,但是存在一些风险,比如实例属性可以在外部被修改。

     为了限制外部操作,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,在这些方法中还可以增加一些检查操作,比如在get_score中增加获取权限操作,在set_score中增加输入检查操作。

    class Student(object):
    
        def __init__(self):
            self._score = 60
    
        def get_score(self):
            print(self._score)
            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
    
    
    if __name__ == "__main__":
        s = Student()
        s.get_score()
        s.set_score("aaa")      # 语法报错

    现在,对任意的Student实例进行操作,就不能随心所欲地设置score了。但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。

    有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!

    第一种方式,使用Python内置的@property装饰器

    @property装饰器就是负责把一个方法变成属性调用的。

    @property的实现比较复杂,我们只考虑如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了装饰器@score.setter,@score.deleter

    装饰器@score.setter负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作。

    装饰器@score.deleter负责控制del操作,项目实际中基本不用。

    class Student(object):
    
        def __init__(self):
            self._score = 60
    
        @property
        def score(self):
            print(self._score)
            return self._score
    
        @score.setter       # 伴生装饰器,只有设置了  @property 才有setter 和 deleter装饰器
        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
            print(f"修改score为{self._score}")
    
        @score.deleter
        def score(self):
            self._score = 0
            print("删除score")
    
    
    if __name__ == "__main__":
        s = Student()
        s.score     # 当获取属性值时执行@property
        s.score = 99    # 当赋值属性值时执行 @**.setter
        del s.score     # 当删除属性值时执行 @**.deleter

    执行结果为:

     第二种方式,使用property()创建类属性

    第二种方式看起来与使用@property装饰器之前的方式相差不大,唯一不同的是使用了property()方法创建了一个类属性

    class Student(object):
    
        def __init__(self):
            self._score = 60
    
        def get_score(self):
            print(self._score)
            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
            print(f"修改score为{self._score}")
    
        def del_score(self):
            self._score = 0
            print("删除score")
    
        score = property(get_score, set_score, del_score)   
    
    if __name__ == "__main__":
        s = Student()
        s.score     # 当获取属性值时,执行property()的第一个方法
        s.score = 99    # 当赋值属性值时,执行property()的第二个方法
        del s.score     # 当删除属性值时执行,执行property()的第三个方法。注意:实际项目中很少用该方法。

    总结

    python有两种方式可以实现既可以检查参数,又可以用类似于直接访问属性的方式访问对象属性。

    第一种:使用Python内置的@property装饰器

    第二种:使用property()创建类属性

    这两种方法最终实现的效果一样,也没有使用限制,喜欢用哪种就用哪种。

  • 相关阅读:
    博客园代码
    前端
    1338. Reduce Array Size to The Half
    1220. Count Vowels Permutation
    363. Max Sum of Rectangle No Larger Than K
    366. Find Leaves of Binary Tree
    443. String Compression
    8 · Rotate String
    886. Possible Bipartition
    LT 183 wood cut
  • 原文地址:https://www.cnblogs.com/testlearn/p/12403036.html
Copyright © 2011-2022 走看看