一文搞懂Python对象的描述器机制
作者:烛阴
在Python中,“描述器”是一种能够自定义对象属性访问(获取、设置、删除)行为的协议,它是实现@property、类属性、ORM字段、类型检查的底层支撑,本文将带你玩转Python对象的描述器机制,需要的朋友可以参考下
一、什么是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,中间会打印“执行了__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 与描述器的关系
你用过的@property,其实就是“非数据描述器”的语法糖:
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):
raise 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, instance, owner):
return self._value
class System:
version = ReadOnly('1.0.0')
print(System.version) # '1.0.0'
到此这篇关于一文搞懂Python对象的描述器机制的文章就介绍到这了,更多相关Python对象描述器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
