news 2026/6/10 23:42:40

描述符(Descriptors)‌

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
描述符(Descriptors)‌

1. 什么是描述符?
描述符是 Python 面向对象编程中一个底层但极其强大的机制。简单来说,‌描述符是一个实现了特定协议(__get__, __set__, __delete__)的类‌。

当你把一个描述符类的实例赋值给另一个类的‌类属性‌时,Python 会自动拦截对该属性的访问、赋值和删除操作,从而让你能够自定义属性的行为。

它是 Python 中 property、classmethod、staticmethod 以及 super() 背后的实现原理。

2. 核心协议方法
一个完整的描述符通常实现以下三个方法中的至少一个:

‌__get__(self, obj, type=None)‌:当访问属性时被调用。
obj:拥有该属性的实例对象(如果是通过类访问,则为 None)。
type:拥有该属性的类。
‌__set__(self, obj, value)‌:当给属性赋值时被调用。
obj:拥有该属性的实例对象。
value:要赋的值。
‌__delete__(self, obj)‌:当删除属性时被调用。

3. 经典应用场景:类型检查与数据验证
假设你想创建一个 Person 类,要求 age 必须是整数且大于 0,name 必须是非空字符串。使用描述符可以完美解耦验证逻辑。

class TypedAttribute: """通用类型检查描述符""" def __init__(self, name, expected_type): self.name = name # 属性名,用于存储真实数据 self.expected_type = expected_type def __get__(self, obj, objtype=None): if obj is None: return self # 从实例的 __dict__ 中获取真实值 return obj.__dict__.get(self.name) def __set__(self, obj, value): if not isinstance(value, self.expected_type): raise TypeError(f"Expected {self.expected_type} for {self.name}, got {type(value)}") #将真实值存入实例的 __dict__ obj.__dict__[self.name] = value def __delete__(self, obj): raise AttributeError(f"Can't delete attribute {self.name}") class Person: # 将描述符实例化为类属性 name = TypedAttribute("name", str) age = TypedAttribute("age", int) def __init__(self, name, age): self.name = name # 触发 TypedAttribute.__set__ self.age = age # 触发 TypedAttribute.__set__ # 测试 p = Person("Alice", 30) print(p.name) # 输出: Alice (触发 __get__) try: del p.name except Exception as e: print(e) # 输出: Can't delete attribute name try: p.age = "thirty" # 触发 __set__,抛出异常 except TypeError as e: print(e) # 输出: Expected <class 'int'> for age, got <class 'str'>

4. 为什么这很重要?

a 代码复用与解偶‌:验证逻辑封装在 TypedAttribute 中,任何类都可以复用它,无需在每个类里重复写 if isinstance...。
‌b 控制属性访问权限‌:可以实现只读属性(只实现 __get__)、懒加载属性(第一次访问时才计算值)等高级功能。
c‌ 理解 Python 底层机制‌:掌握描述符是理解 Python 如何管理属性查找顺序(MRO + Descriptor Protocol)的关键。

5. 数据描述符 vs 非数据描述符

  • 数据描述符‌:实现了__set____delete__。优先级‌高于‌实例字典 (obj.__dict__)。
  • 非数据描述符‌:只实现了__get__。优先级‌低于‌实例字典。
    • 这就是为什么你可以用实例属性覆盖方法(方法是函数,属于非数据描述符),但不能覆盖property(property 是数据描述符)。

6 最佳实践建议
不要过度使用‌:对于简单的属性验证,内置的 @property 装饰器通常更简洁易读。
适用场景‌:当你需要在多个类中复用复杂的属性逻辑(如 ORM 框架中的字段映射、严格的类型系统、缓存机制)时,描述符是最佳选择。
注意命名冲突‌:在 __init__ 中给描述符传参时,务必确保存储数据的键名(如上面的 self.name)不与描述符本身的类属性名冲突,通常建议存储在 obj.__dict__ 中并使用唯一键名。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 23:41:46

臭氧层空洞是否正在悄悄逼近你的头顶? - 蓝色星球

当我们谈论“蓝天保卫战”时&#xff0c;大家脑海里浮现的往往是雾霾散去后那抹罕见的湛蓝&#xff0c;或者是空气净化器滤芯更换时那声沉重的叹息。很少有人会把目光投向平流层&#xff0c;去关注那里那层薄薄的、看不见的“保护伞”是否正在修补。 但在昨天&#xff0c;生态环…

作者头像 李华
网站建设 2026/6/10 23:39:16

16.5LangChain 与 LangGraph 记忆管理策略完整代码演示

LangChain 与 LangGraph 记忆管理策略完整代码演示 本文将用多个独立、可运行的代码示例&#xff0c;逐一演示 LangChain 中短期记忆、长期记忆以及LangGraph 的 Checkpointer 会话记忆&#xff0c;并覆盖修剪、删除、总结等高级记忆管理策略。所有示例均基于阿里云百炼 Qwen 模…

作者头像 李华
网站建设 2026/6/10 23:38:18

Teamcenter许可回收,两种触发方式到底哪个更及时?

做个简单的调研&#xff0c;同样用Teamcenter&#xff0c;同样面对许可“等米下锅”的窘境&#xff0c;我发现大家回收集群的方式真是天差地别。前几年听说一家机械厂&#xff0c;IT老大为了抢到工程师独占的许可证&#xff0c;竟每晚11点守在系统前手动踢人——谁不开电脑就回…

作者头像 李华
网站建设 2026/6/10 23:37:10

Linux Schedutil 的 sugov_policy:调频策略的 per-CPU 管理

一、简介在现代 Linux 系统中&#xff0c;CPU 频率调频&#xff08;CPUFreq&#xff09;是衔接进程调度子系统与硬件电源管理的核心模块&#xff0c;直接决定系统的性能、功耗、发热三者的平衡。传统ondemand、performance等调频策略依赖独立定时器轮询 CPU 负载&#xff0c;调…

作者头像 李华
网站建设 2026/6/10 23:33:02

3分钟快速激活Beyond Compare 5:开源密钥生成工具完整指南

3分钟快速激活Beyond Compare 5&#xff1a;开源密钥生成工具完整指南 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否厌倦了Beyond Compare 5的30天评估期限制&#xff1f;想要永久解锁这…

作者头像 李华
网站建设 2026/6/10 23:32:59

PLC客控方案如何赢得亚朵集团招标?选型要点全解析

酒店智能客控市场进入精细化竞争阶段&#xff0c;技术方案从早期的RCU集中控制、RS-485总线&#xff0c;逐步向利用现有电力线传输信号的方向演进。PLC&#xff08;电力线通信&#xff09;技术因其无需额外布通信线、网随电通、施工成本低等特性&#xff0c;在中高端连锁酒店的…

作者头像 李华