专栏首页面向人生编程关于 Python 描述符(Descriptor) 附实例
原创

关于 Python 描述符(Descriptor) 附实例

在 Python 众多原生特性中,描述符可能是最少被自定义实现的特性之一,很多初学者都可能不知道它的存在,但它在底层实现的方法和属性却随处可见,它优雅的实现方式充分体现出 Python 的简洁之美。

定义

  • 描述符(descriptor):是一个有"绑定行为"的对象属性(object attribute),它的访问控制会被描述器协议方法重写。
  • 任何定义了 __get__, __set__ 或者 __delete__ 任一方法的类称为描述符类,其实例对象便是一个描述符,这些方法称为描述符协议。
  • 当对一个实例属性进行访问时,Python 会按 obj.__dict__type(obj).__dict__type(obj)的父类.__dict__ 顺序进行查找,如果查找到目标属性并发现是一个描述符,Python 会调用描述符协议来改变默认的控制行为。
  • 描述符是 @property @classmethod @staticmethodsuper 的底层实现机制。

特性

  • 同时定义了 __get____set__ 的描述符称为 数据描述符(data descriptor);仅定义了 __get__ 的称为 非数据描述符(non-data descriptor) 。两者区别在于:如果 obj.__dict__ 中有与描述符同名的属性,若描述符是数据描述符,则优先调用描述符,若是非数据描述符,则优先使用 obj.__dict__ 中属性。
  • 描述符协议必须定义在类的层次上,否则无法被自动调用。

描述符协议

__get__(self, instance, owner)

:param self: 描述符对象本身

:param instance: 使用描述符的对象的实例

:param owner: 使用描述符的对象拥有者

__set__(self, instance, value)

:param value: 对描述符的赋值

__delete__(self, instance)

实例

    class LazyProperty(object):
        """
        实现惰性求值(访问时才计算,并将值缓存)
        利用了 obj.__dict__ 优先级高于 non-data descriptor 的特性
        第一次调用 __get__ 以同名属性存于实例字典中,之后就不再调用 __get__
        """
        def __init__(self, fun):
            self.fun = fun

        def __get__(self, instance, owner):
            if instance is None:
                return self
            value = self.fun(instance)
            setattr(instance, self.fun.__name__, value)
            return value

    class ReadonlyNumber(object):
        """
        实现只读属性(实例属性初始化后无法被修改)
        利用了 data descriptor 优先级高于 obj.__dict__ 的特性
        当试图对属性赋值时,总会先调用 __set__ 方法从而抛出异常
        """
        def __init__(self, value):
            self.value = value

        def __get__(self, instance, owner):
            return self.value

        def __set__(self, instance, value):
            raise AttributeError(
                "'%s' is not modifiable" % self.value
             )

    class Circle(object):

        pi = ReadonlyNumber(3.14)

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

        @LazyProperty
        def area(self):
            print('Computing area')
            return self.pi * self.radius ** 2

参考文章

https://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python描述器

    以上代码实现了温度的摄氏温度和华氏温度之间的自动转换。其中Temperature类含有实例变量fahrenheit和类变量celsius,celsius由描述器...

    职场亮哥
  • OpenCV4.5.1 | 使用一行代码将图像匹配性能提高14%

    opencv4.5.1中最令人兴奋的特性之一是BEBLID(Boosted effective Binary Local Image Descriptor),它...

    AI算法与图像处理
  • 有效的python属性管理:描述符的使用

    專 欄 ❈Pytlab,Python中文社区专栏作者。主要从事科学计算与高性能计算领域的应用,主要语言为Python,C,C++。熟悉数值算法(最优化方法,蒙...

    Python中文社区
  • 深入理解 Python 的属性查找

    今天我们了解下python的属性查找,在Python中,属性查找(attribute lookup)是比较复杂的,特别是涉及到描述符descriptor的时候。...

    企鹅号小编
  • python学习笔记6.5-类中描述符的使用

    描述符(Descriptor)就是以特殊方法get(), set(), delete()的形式实现了三个核心的属性访问操作(set,get,delete)的类。...

    锦小年
  • Python中反射和描述器总结

    在Python中,能够通过一个对象,找出type、class、attribute或者method的能力,成为反射。

    py3study
  • 修改一行代码,将图像匹配效果提升14%

    OpenCV发布了4.5.1,包含了BEBLID算子,一个新的局部特征描述符,超越ORB。

    计算机视觉
  • 有的UE画不好PPT,好的测试却靠Python加薪

                     测试开发者的共同关注! 作者:jhouyang,腾讯资深后台开发工程师。 WeTest导读 想要升职加薪,强大的专业能力很...

    WeTest质量开放平台团队
  • ES6装饰器Decorator的实现原理

    NOTE Decorators are an experimental feature that may change in future releases...

    伯爵

扫码关注云+社区

领取腾讯云代金券