当前位置: 移动技术网 > IT编程>脚本编程>Python > Python-通过属性描述符管理实例属性

Python-通过属性描述符管理实例属性

2020年07月14日  | 移动技术网IT编程  | 我要评论
上一篇博客中,我们通过@property装饰器来管理实例的属性,这使得我们不仅可以通过obj.attr的方式来访问,并且可以设置属性的存储规则。并且由于@property和@attr.setter装饰器的存在,我们也很容易能够找到处理业务逻辑相关的函数。但当大量的属性都需要相同的存储逻辑来进行控制时,使用@property装饰器仍然无法避免代码的重复。例如:学生类的age和grades属性都必须是整数并且大于0.下面通过属性描述符的形式来管理实例属性,看看有什么区别class IntField(obje

上一篇博客中,我们通过@property装饰器来管理实例的属性,这使得我们不仅可以通过obj.attr的方式来访问,并且可以设置属性的存储规则。并且由于@property和@attr.setter装饰器的存在,我们也很容易能够找到处理业务逻辑相关的函数。但当大量的属性都需要相同的存储逻辑来进行控制时,使用@property装饰器仍然无法避免代码的重复。例如:学生类的age和grades属性都必须是整数并且大于0.
下面通过属性描述符的形式来管理实例属性,看看有什么区别

class IntField(object):

    def __init__(self,attribute):
        self.attribute = attribute

    def __get__(self, instance, owner):
        print("get:" + str(instance) + "的" + str(self.attribute),owner)
        return instance.__dict__[self.attribute]

    def __set__(self, instance, value):
        print("set:" + str(instance) + "的" + str(self.attribute))
        if isinstance(value,int) and value >=0:
            instance.__dict__[self.attribute] = value
            self.values = value
        else:
            raise ValueError


class Student(object):

    age = IntField("age")
    grades = IntField("grades")

    def __init__(self,name,age,grades):
        self.name = name
        self.age =age # 调用age.setter方法
        self.grades =grades

    def graduate(self):
        if self.grades >= 60:
            print("允许毕业")
        else:
            print("留级查看")

s = Student("jack",22,88)
s2 = Student("tom",25,77)
print(s.age)
print(s2.age)
print(s.__dict__)
print(s2.__dict__)
set:<__main__.Student object at 0x000000000220C4E0>的age
set:<__main__.Student object at 0x000000000220C4E0>的grades
set:<__main__.Student object at 0x000000000281A198>的age
set:<__main__.Student object at 0x000000000281A198>的grades
get:<__main__.Student object at 0x000000000220C4E0>的age <class '__main__.Student'>
22
get:<__main__.Student object at 0x000000000281A198>的age <class '__main__.Student'>
25
{'name': 'jack', 'age': 22, 'grades': 88}
{'name': 'tom', 'age': 25, 'grades': 77}

在分析上面一个 例子前我们先了解关于属性描述符的概念

  • 描述符类:实现了描述符协议的类。只要实现__get__,__set__和__delete__3个方法中的任意一个,这个类就是描述符。如上面例子中的IntField类。它能实现对多个属性运用相同存取逻辑的一种方式。通俗来说就是:创建一个实例,作为另一个类的类属性
  • 托管类:将描述符类的实例作为类属性的类,如上面例子中的Student类,
  • 数据描述符(data descriptor):如果一个对象同时定义了__get__和__set__方法 ,它被称做数据描述符
  • 非数据描述符(non-data descriptor):只定义__get__方法的对象则被称之为非数据描述符

分析:

  • 当我们通过s.age这种方式来访问实例属性的时候,实际上是调用描述符实例的__get__方法进行访问的
  • 当我们通过s.age = age 来给实例属性赋值的时候,实际上是调用的描述符实例的__set__方法,并且在__set__方法中,传入了实例对象instance和该对象所属的类owner。在__set__方法中来定义属性的存储规则,然后通过instance.__dict__[self.attribute] = value这种形式来进行实例属性的绑定。这样就保证了实例s和s2的相互独立,互不影响。
  • 如果我们需要给Student类添加一个新的属性学分credit,学分为整数,且大于0。存储规则同age和grades相同。这样我们只需要在Student类中添加一个类属性credit = IntField(“credit”)。这样比@property装饰器要简洁许多。

本文地址:https://blog.csdn.net/weixin_43989215/article/details/107303683

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网