• Python动态属性有什么用


    Python 动态属性的概念可能会被面试问到,在项目当中也非常实用,但是在一般的编程教程中不会提到,可以进修一下。

    先看一个简单的例子。创建一个 Student 类,我希望通过实例来获取每个学生的一些情况,包括名字,成绩等。成绩只有等到考试结束以后才会有,所以实例化的时候不会给它赋值。

    class Student:
        def __init__(self, name):
            self.name = name
            self.score = None
    
    mike = Student('mike')
    

    考试完以后,准备给 mike 打分:

    mike.score = 999
    

    在这里,老师一不小心多打了个 9 ,通常来说打分都是 100 分值,999 是一个非法数据,不应该赋值成功。学生一多,老师打分出现手误的情况肯定会越来越多,所以我们必须想办法修改程序,限制 score 的值必须在 0-100 分。

    限制值

    我们定义一个方法,如果输入的不是 0-100 的整数,就让程序报错,数据合法,我们就把 score 属性修改成功。

    def set_score(self, new_score):
        if not isinstance(new_score, int):
            raise ValueError('score must be int')
    
        if 0 <= new_score <= 100:
            self.score = new_score
            return self.score
        else:
            raise ValueError('score invalid')
    

    这样我们每次需要获取成绩的时候使用 self.score 获取,修改成绩的时候调用函数来修改:

    mike.set_score(999)
    

    调用以后会报错,因为 999 是非法数据。注意,这个时候我使用 self.score 还是可以进行设置,而且不报错:

    self.score = 999
    

    这显然是不行的。所以我们要提供一种机制,把 score 变成私有属性,不能让外部访问。很遗憾,python 的私有属性是伪私有。通常我们把 _ 开头的属性叫私有属性,但是这只是一种协议和规定,你看到下划线开头的属性,不要去访问了。你硬要访问,是可以的,python 并不会禁止。

    使用 @property 的方式代替。

    上面的方法虽然实现了功能,但是改变了属性的使用方式。平常是这样使用的:

    # 获取属性
    a = mike.score
    # 设置属性
    mike.score = 99
    
    @property
    def score(self):
        return self._score
    
    @score.setter
    def score(self, new_score):
        if not isinstance(new_score, int):
            raise ValueError('score must be int')
    
            if 0 <= new_score <= 100:
                self._score = new_score
                return self._score
            else:
                raise ValueError('score invalid')
    

    动态属性的好处

    • 统一了调用方式。self.score = 99 的方式,而不是函数调用的方式。
    • _score 我们就不直接去使用了。你要用也可以,不建议。
    • 如果我们一个属性只可以读,把 setter 部分注释掉就可以了。

    现在我们来完善这个类,添加 birth 属性和年龄属性:

    from datetime import datetime
    
    class Student:
        def __init__(self, name, birth=1920):
            self.name = name
            self._score = None
            self.birth = birth
            self.age = datetime.now().year - self.birth
    
    
    mike = Student('mike')
    print(mike.birth)
    print(mike.age)
    
    • birth 和 age 这两个是可以根据一个求出另外一个的。存在数据冗余问题。

    • age 属性这样是有问题的。mike 初始化的时候,age 已经被求出来了,如果我在下一年再去访问 age 属性,那他就是个错误的值。可以通过把 age 设成现在的秒数来验证:

      self.age = datetime.now().second
      
      mike = Student('mike')
      time.sleep(5)
      print(mike.age)
      print(datetime.now().second)
      

    动态显示

    @property
    def age(self):
        return datetime.now().year - self.birth
    

    注意,这里不要去设置 @age.setter ,因为他是动态变化的,你修改了会造成数据不一致,它只能作为一个只读属性。

    @property 作用和应用场景:

    • @property 优化了属性读取和设置的可读性
    • 需要限制属性的特征;
    • 只读属性。如果属性只可以读,不可以写,用起来很方便。
    • 这个属性根据一个变化的环境动态改变。

    我是九柄,公众号【 九柄 】,分享软件测试文章、面试、教程资料,欢迎来看看。

  • 相关阅读:
    图算法(一)——基本图算法(BFS,DFS及其应用)(1)
    设置drawable图片
    view的加载
    onSaveInstanceState和onRestoreInstanceState
    android中的生命周期(新增2个函数)
    int integer string间的转换
    andorid中Html.fromHtml方法
    android获取inflater
    android中获取string字符串的方法
    c#基础试题
  • 原文地址:https://www.cnblogs.com/heniu/p/16503147.html
Copyright © 2020-2023  润新知