Python-通过属性描述符管理实例属性
程序员文章站
2022-04-27 16:57:50
上一篇博客中,我们通过@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
推荐阅读
-
Vue中通过属性绑定为元素绑定style行内样式的实例代码
-
python 通过xml获取测试节点和属性的实例
-
Python-通过属性描述符管理实例属性
-
JS和jQuery通过this获取html标签中的属性值(实例代码)
-
jQuery通过id属性来获取元素,通过.addClass()方法来添加class.(实例分析)
-
C#如何通过对象属性名修改值的实例
-
Vue中通过属性绑定为元素绑定style行内样式的实例代码
-
Spring Bean管理(bean简介,bean中主要属性,bean实例化)
-
JavaScript通过prototype给对象定义属性用法实例_javascript技巧
-
JavaScript中通过prototype属性共享属性和方法的技巧实例_javascript技巧