描述符

描述符 允许你自定义在引用一个对象的属性时应该完成的事情

描述符是python中复杂属性访问的基础。它在内部用于实现property,方法,类方法,静态方法和super类型。它是一个类可以将属性管理委托给另一个类

描述符类基于三个特殊方法,这三个方法组成了描述符协议

get
在设置属性时将调用这一方法(被称为 getter)
set
在设置属性时将调用这一方法(被称为 setter)
delete
对属性调用del时将调用这一方法

实现了__get__()和__set__()的描述符被称为数据描述符。如果只实现了__get__()被称为非数据描述符

在每次属性查找中,这个协议的方法实际上由对象的特殊方法__getattribute__()调用。每次通过点号(instance.attrbute)函数调用执行查找,每次都会隐式的调用__getattribute__()。它会按照以下顺序查找该属性:

  • 验证该属性是否为实列的类对象的数据描述符
  • 如果不是,就查看该属性是否能在实列的类对象的__dic__中找到
  • 最后,查看该属性是否为实列的类对象的非数据描述符

数据描述符优先于__dict__查找,而__dict__优先于非数据描述符。

class RevealAccess(object):
    '''一个数据描述符,正常设定值并返回值,同时打印出访问的信息'''

    def __init__(self,initval=None,name="var"):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print("取出",self.name)
        return self.val

    def __set__(self, obj, val):
        print("设置",self.name)
        self.val = val

    def __delete__(self, instance):
        print("删除",self.name)

class MyClass(object):
    x = RevealAccess(10,'var "X"')
    y = 5

m = MyClass()
print(m.x)
m.x=99
print(m.x)
del m.x

运行上述代码得到

描述符_第1张图片

通过示列清楚能得到,如果一个类的某个属性有描述符,那么查找这个属性时,都会调用描述符的__get__()方法并返回它的值,每次对这个属性赋值都会调用__set__(),每次通过删除del 删除一个属性时会调用__delete__()。

描述符的一个示列用法是将类的属性初始化延迟到被实列访问。如果这些属性的初始化以来全局应用上下文,可以设置访问权限,检查更改参数等,示列代码如下。

class InitOnAccess(object):

    def __init__(self,klass,*args,**kwargs):
        self.klass = klass
        self.args = args
        self.kwargs = kwargs
        self._initialized = None

    def __get__(self, instance, owner):
        if self._initialized is None:
            print("已初始化")
            self._initialized = self.klass(*self.args,**self.kwargs)
        else:
            print("隐藏不可见")
        return self._initialized

class MyClass(object):
    lazily_initialzed = InitOnAccess(list,"argument")

m = MyClass()
print(m.lazily_initialzed)
print(m.lazily_initialzed)

描述符_第2张图片

property提供了一个内置的描述符类型,它是以装饰器的形式将一个属性链接到一组方法上。property是在调用属性时触发,property.setter是把一个setter方法变成属性赋值。创建property的最佳语法是使用property作为装饰器。

class Rectangle:

    def __init__(self,x1,y1,x2,y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2

    @property
    def width(self):
        """从顶部测量的矩形高度"""
        print("width.property")
        return self.x2 - self.x1

    @width.setter
    def width(self,value):
        print("width.setter")
        self.x2 = self.x1 + value

    @property
    def height(self):
        """从顶部测量的矩形高度"""
        print("height.property")
        return self.y2 - self.y1

    @height.setter
    def height(self,value):
        print("height.setter")
        self.y2 = self.y1 + value

cone = Rectangle(x1=20,y1=15,x2=10,y2=5)
print(cone.width)
cone.width = 100
print(cone.width)
print('-'*20)
print(cone.height)
cone.height = 99
print(cone.height)

描述符_第3张图片

你可能感兴趣的:(python)