当前位置: 首页 > 编程笔记 >

Python进阶之@property动态属性的实现

司徒阳曜
2023-03-14
本文向大家介绍Python进阶之@property动态属性的实现,包括了Python进阶之@property动态属性的实现的使用技巧和注意事项,需要的朋友参考一下

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍Python 类,property属性(简化属性的操作),@property,property()用法示例,包括了Python 类,property属性(简化属性的操作),@property,property()用法示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python 类,property属性(简化属性的操作),@property,property()用法。分享给

  • 本文向大家介绍python进阶教程之动态类型详解,包括了python进阶教程之动态类型详解的使用技巧和注意事项,需要的朋友参考一下 动态类型(dynamic typing)是Python另一个重要的核心概念。我们之前说过,Python的变量(variable)不需要声明,而在赋值时,变量可以重新赋值为任意值。这些都与动态类型的概念相关。 动态类型 在我们接触的对象中,有一类特殊的对象,是用于存储数

  •  属性可以像变量那样进行读写,但实际上,在读写时会像调用函数那样调用设置函数 ( setter ) 和读取函数 ( getter ) 。设置函数 和 读取函数有时也被称为 属性控制器。  定义格式如下。 property标识符 { setter(参数) { //这里是设定函数的内容 } getter() { //这里是读取函数的内容 return表达式;//读取函数的返回值 } }  把 sett

  • 动态类型(dynamic typing)是Python另一个重要的核心概念。我们之前说过,Python的变量(variable)不需要声明,而在赋值时,变量可以重新赋值为任意值。这些都与动态类型的概念相关。 动态类型 在我们接触的对象中,有一类特殊的对象,是用于存储数据的。常见的该类对象包括各种数字,字符串,表,词典。在C语言中,我们称这样一些数据结构为变量。而在Python中,这些是对象。 对象

  • 问题内容: 我知道我可以通过执行以下操作来向对象动态添加实例方法: 稍后我可以打电话给我,自我将被正确绑定,一切正常。 现在,我的问题是:如何做完全相同的事情来获得用@property装饰新方法的行为? 我猜是这样的: 但是,这样做会返回一个属性对象。 问题答案: 在描述对象需要住 类 , 未 在 实例中 ,有你想要的效果。如果您不想更改现有的类以避免更改其他实例的行为,则需要创建“每个实例的类”

  • 本文向大家介绍Flutter进阶之实现动画效果(十),包括了Flutter进阶之实现动画效果(十)的使用技巧和注意事项,需要的朋友参考一下 前面的两篇文章【动画效果(八) 、动画效果(九) 】中,我们只需要统计产品和地区,如果现在增加一个统计项目——销售渠道,那么使用之前的堆叠条形图和分组条形图都不适合。我们可以将两者结合,使用分组+堆叠条形图,实际效果如下图所示: 如上图,我们使用同一种颜色的不