开发者

一文搞懂Python对象的描述器机制

目录
  • 一、什么是python描述器?
  • 二、描述器协议:三大魔法方法
  • 三、入门实战:搞懂描述器工作的方式
    • 3.1 数据描述器 VS 非数据描述器
    • 3.2 数据描述器基础案例
  • 四、@property 与描述器的关系
    • 五、进阶:自定义描述器封装与通用实现
      • 5.1 描述器工厂 基于装饰器快速生成校验字段
      • 5.2 只读属性描述器

    一、什么是Python描述器?

    在Python中,“描述器”是一种能够自定义对象属性访问(获取、设置、删除)行为的协议。它是实现@property、类属性、ORM字段、类型检查的底层支撑。

    一句话解释:只要一个对象定义了__get____set____delete__等特殊方法,并作为另一个类的类属性,这个对象就成了描述器!

    默认对属性的访问控制是从对象的字典里面 (__dict__) 中获取 (get) , 设置 (set) 和删除 (delete) 。

    举例来说, a.x 的查找顺序是, a.__dict__['x'] , 然后 type(a).__dict__['x'] , 然后找 type(a) 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。

    二、描述器协议:三大魔法方法

    方法作用用法场景
    __get__获取属性时调用动态计算、懒加载
    __set__设置属性时调用数据验证、只读限制
    __delete__删除属性时调用管控属性生命周期

    最简单的描述器雏形:

    class DemoDescriptor:
        def __get__(self, instance, owner):
            print('执行了__get__')
            return 42
    
    class MyClass:
        x = DemoDescriptor()
    
    obj = MyClass()
    print(obj.x)  # 输出42,中间会打印“执行了android__get__”
    

    三、入门实战:搞懂描述器工作的方式

    3.1 数据描述器 VS 非数据描述器

    • 数据描述器 : 同时定义了__get____set__
    • 非数据描述器 : 只定义了__get__

    数据描述器拥有更高优先级,会屏蔽实例字典上的同名属性!

    3.2 数据描述器基础案例

    class Typed:
        def __init__(self, name, typ):
            self.name = name
            self.typ = typ
    
        def __get__(self, instance, owner):
            return instance.__dict__[self.name]
    
        def __set__(self, instance, value):
            if not isinstance(value, self.typ):
                raise TypeError(f'属性{self.name}必须是{self.typ}')
            instance.__dict__[self.name] = value
    
    class Person:
        age = Typed('age', int)    # 用描述器控制
        name = Typed('name', str)
    
    p = Person()
    p.age = 18            # 自动类型检查
    p.name = '小明'
    # p.age = 'not int'   # 抛出TypeError
    

    四、@property 与描述器的关系

    你用过的@prjsoperty,其实就是“非数据描述器”的语法糖:

    class Demo:
        @property
        def val(self):
            return 666
    

    底层实现和你定义带__get__的对象如出一辙。

    五、进阶:自定义描述器封装与通用实现

    5.1 描述器工厂 基于装饰器快速生成校验字段

    def typed_field(name, typ):
        class _TypedDescriptor:
            def __get__(self, instance, owner):
                return instance.__dict__[name]
            def _编程客栈_set__(self, instance, value):
                if not isinstance(value, typ):
                    raiYfNQpVpAxGse TypeError(f"属性{name}必须是{typ}")
                instance.__dict__[name] = value
        return _TypedDescriptor()
    
    class Student:
        age = typed_field('age', int)
        name = typed_field('name', str)
    
    stu = Student()
    stu.age = 18    # √
    # stu.age = 'oops' # TypeError
    

    5.2 只读属性描述器

    class ReadOnly:
        def __init__(self, value):
            self._value = value
        def __get__(self, http://www.devze.cominstance, owner):
            return self._value
    
    class System:
        version = ReadOnly('1.0.0')
    
    print(System.version)   # '1.0.0'
    

    到此这篇关于一文搞懂Python对象的描述器机制的文章就介绍到这了,更多相关Python对象描述器内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜