详细介绍:解锁Python的强大能力:深入理解描述符

news/2026/1/21 16:11:35/文章来源:https://www.cnblogs.com/ljbguanli/p/19512410

详细介绍:解锁Python的强大能力:深入理解描述符

在Python的世界里,你可能已经在不知不觉中使用了描述符。@property 装饰器让方法像属性一样被访问,这优雅的背后,正是描述符在默默支撑。描述符是Python高级编程中一项核心技巧,它赋予了开发者精细化控制属性访问的能力,是构建强大、灵活且安全的代码基石的利器。

一、 什么是描述符?一个简单的比喻

首先,让我们抛开晦涩的定义。想象一个智能银行的保险箱。

  • 保险箱本身(对象):拥有各种属性,比如“门牌号”、“颜色”。
  • 保险箱里的金条(普通属性):你可以直接存取,就像 obj.attribute
  • 保险箱的密码锁(描述符):这个锁很特殊。当你尝试打开(获取) 它时,它会要求你先输入密码验证;当你尝试修改(设置) 密码时,它又会要求你提供旧密码。这个“密码锁”不是一个简单的值,而是一套访问规则

在Python中,描述符就是一个实现了特定协议(__get__, __set__, __delete__)的类。它不是一个独立的物体,而是“依附”于另一个类的属性,并控制着对这个属性的访问。

二、 描述符协议:三大核心方法

一个类只要实现了以下一个或多个方法,它就成为了一个描述符:

  1. __get__(self, instance, owner)
    • 何时触发:当您访问属性时(如 obj.attr)。
    • 参数
      • self:描述符实例本身。
      • instance:被访问的对象实例(如果是通过类访问,如 Class.attr,此值为 None)。
      • owner:拥有该描述符的
    • 返回值:返回给用户的值。
  2. __set__(self, instance, value)
    • 何时触发:当您为属性赋值时(如 obj.attr = value)。
    • 参数
      • self:描述符实例本身。
      • instance:被访问的对象实例。
      • value:要设置的值。
  3. __delete__(self, instance)
    • 何时触发:当您删除属性时(如 del obj.attr)。
    • 参数
      • self:描述符实例本身。
      • instance:被访问的对象实例。

根据实现的方法,描述符分为两类:

这个区别至关重要,因为它关系到Python的属性查找优先级

三、 属性查找的优先级

当您访问 obj.attr 时,Python解释器会按照以下顺序查找:

  1. 数据描述符(最高优先级)
  2. 实例属性obj.__dict__ 中的值)
  3. 非数据描述符
  4. 类属性(普通变量)
  5. 查找父类(继承链)
  6. 调用 __getattr__(如果存在)

这意味着,如果一个名称被一个数据描述符占领了,那么即使你在实例中给这个属性赋值,也只会触发描述符的 __set__ 方法,而不会覆盖它。这保证了描述符对属性访问的绝对控制权。

四、 从零开始:亲手实现一个描述符

理论说再多,不如动手写一个。我们来创建一个经典且实用的描述符:类型验证描述符

class TypedAttribute:
"""一个类型验证描述符,确保属性被设置为指定的类型。"""
def __init__(self, type_):
self.type_ = type_
# 使用一个实例名称作为key的字典来存储数据,避免直接存储在描述符上
self._storage = {}
def __get__(self, instance, owner):
# 如果是通过类访问(如 Person.name),返回描述符本身
if instance is None:
return self
# 否则,从存储中返回该实例对应的值
return self._storage.get(instance, None)
def __set__(self, instance, value):
# 在设置值之前进行类型检查
if not isinstance(value, self.type_):
raise TypeError(f"Expected {self.type_.__name__}, got {type(value).__name__}")
# 通过实例作为key来存储值
self._storage[instance] = value
def __delete__(self, instance):
# 删除该实例对应的值
if instance in self._storage:
del self._storage[instance]
# 使用我们的描述符
class Person:
name = TypedAttribute(str)  # name 必须是一个字符串
age = TypedAttribute(int)   # age 必须是一个整数
def __init__(self, name, age):
self.name = name  # 这里会触发 TypedAttribute.__set__
self.age = age    # 这里会触发 TypedAttribute.__set__
# 测试
try:
alice = Person("Alice", 30)
print(alice.name)  # 输出: Alice
alice.age = 31     # 正常
print(alice.age)   # 输出: 31
alice.age = "31"   # 触发 TypeError: Expected int, got str
except TypeError as e:
print(e)

这个例子清晰地展示了描述符如何工作:

  • 我们将 nameage 定义为类的类属性,其值是描述符实例。
  • 当我们对实例的 nameage 进行赋值或访问时,实际上是在调用描述符的 __set____get__ 方法。

注意:上面的 _storage 字典方式有一个内存泄漏问题(实例不会被垃圾回收),在实际生产中,使用 weakref.WeakKeyDictionary 是更好的选择。

五、 现实中的应用:@property 的本质

现在,我们可以揭晓 @property 的神秘面纱了。它本质上就是一个非数据描述符的语法糖!

# 使用 @property 的常见方式
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""获取半径"""
return self._radius
@radius.setter
def radius(self, value):
"""设置半径,必须为正数"""
if value <= 0:
raise ValueError("Radius must be positive.")
self._radius = value
@property
def area(self):
"""计算面积,这是一个只读属性"""
return 3.14159 * self._radius ** 2

上面的代码等价于用描述符手动实现:

class Property:
"""一个简化的property模拟"""
def __init__(self, fget=None, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, instance, owner):
if instance is None:
return self
return self.fget(instance)
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(instance, value)
def setter(self, fset):
# 返回一个新的描述符,它包含了getter和新的setter
return type(self)(self.fget, fset)
# 手动使用(不优雅,但揭示了原理)
class CircleManual:
def __init__(self, radius):
self._radius = radius
def _get_radius(self):
return self._radius
def _set_radius(self, value):
if value <= 0:
raise ValueError("Radius must be positive.")
self._radius = value
radius = Property(_get_radius, _set_radius) # 看,这里就是一个描述符实例!

可见,@property 让创建描述符变得异常简单和优雅。

六、 描述符的使用场景与最佳实践

何时使用描述符?

  1. 数据验证与转换:如上文的 TypedAttribute,确保数据符合预期。
  2. 惰性求值:当一个属性的计算成本很高时,可以只在第一次访问时计算并缓存结果。
  3. 访问控制与日志:记录对某个属性的所有访问和修改操作。
  4. 实现ORM框架:这是描述符最经典的应用之一。在Django ORM或SQLAlchemy中,当你定义一个模型字段 name = models.CharField(...) 时,CharField 就是一个描述符。它负责在内存对象和数据库列之间进行双向转换。

最佳实践

  • 使用 weakref:避免在描述符中直接存储实例数据导致的内存泄漏。

  • 新的Python特性:在Python 3.6+中,可以使用 __set_name__ 方法自动获取描述符在类中被赋予的属性名,这解决了上面例子中需要手动传递名字的问题。

    class ModernDescriptor:
    def __set_name__(self, owner, name):
    self.name = name # 自动知道它在类中被叫做什么
    def __get__(self, instance, owner):
    if instance is None:
    return self
    return instance.__dict__.get(self.name)
    def __set__(self, instance, value):
    # 这里可以直接存储在 instance.__dict__ 中,覆盖非数据描述符
    instance.__dict__[self.name] = value
七、 总结

描述符是Python元编程能力的杰出代表。它初看复杂,但一旦掌握,你将获得对面向对象编程更深层次的理解和控制力。

  • 核心:描述符是一个实现了 __get__, __set__, __delete__ 的类。
  • 关键:理解数据描述符非数据描述符在属性查找链中的不同优先级。
  • 应用:从简单的 @property 到复杂的ORM框架,描述符无处不在。
  • 价值:它提供了一种可复用的机制,将属性访问逻辑封装起来,使代码更清晰、健壮和强大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1195356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物联网墨水屏电子价签可以支持NFC刷新吗?

随着通信技术的持续演进&#xff0c;Wi-Fi、蓝牙、NFC乃至新兴的星闪等技术不断推动物联网设备的连接方式多样化&#xff0c;也为各类智能硬件提供了灵活更新与管理的可能。在零售、仓储、办公等场景中广泛应用的墨水屏电子价签&#xff0c;其信息刷新方式自然成为用户关注的焦…

2026年复合管激光堆焊厂家排名,广东好用的厂家推荐

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家防腐防磨堆焊领域标杆企业,为工业客户选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:广东博盈特焊技术股份有限公司 推荐指数:★★★★★ | 口…

TurboDiffusion影视应用案例:分镜动态预览系统快速搭建教程

TurboDiffusion影视应用案例&#xff1a;分镜动态预览系统快速搭建教程 1. 引言&#xff1a;为什么影视创作需要TurboDiffusion&#xff1f; 在传统影视制作流程中&#xff0c;分镜预览&#xff08;Animatic&#xff09;是前期策划的关键环节。导演和美术团队通常要花费数小时…

AI推理框架选型指南:SGLang开源优势+GPU适配入门必看

AI推理框架选型指南&#xff1a;SGLang开源优势GPU适配入门必看 在当前大模型快速发展的背景下&#xff0c;如何高效部署和调用LLM&#xff08;大语言模型&#xff09;成为开发者关注的核心问题。传统的推理方式往往面临吞吐低、延迟高、编程复杂等问题&#xff0c;尤其在多轮…

MCP服务器resources动态扩展实践:应对高并发的4步速成方案

第一章&#xff1a;MCP服务器resources动态扩展的核心机制 MCP&#xff08;Microservice Control Plane&#xff09;服务器的 resources 动态扩展机制&#xff0c;是支撑其高可用性与弹性伸缩能力的关键设计。该机制不依赖静态配置或重启生效&#xff0c;而是通过实时感知负载变…

2026朝阳市英语雅思培训辅导机构推荐,2026权威出国雅思课程排行榜

依托英国文化教育协会最新雅思备考数据、朝阳市本地调研,结合朝阳县、建平县、喀喇沁左翼蒙古族自治县考生实战反馈,本次对区域内雅思培训市场开展全面深度测评,旨在破解考生选课难、提分慢、技巧薄弱等核心痛点,为…

低成本部署GPT-OSS-20B?微调显存需求与优化方案

低成本部署GPT-OSS-20B&#xff1f;微调显存需求与优化方案 1. GPT-OSS-20B是什么&#xff0c;为什么值得关注&#xff1f; 你可能已经听说过OpenAI最新开源的GPT-OSS系列模型&#xff0c;而其中的GPT-OSS-20B正成为社区关注的焦点。它不是简单的闭源模型复刻&#xff0c;而是…

2026年权威数据资产变现品牌方案推荐

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家标杆企业,为企业选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:广东省空间计算科技集团有限公司 推荐指数:★★★★★ | 口碑评分:国内首推诚…

2026年探讨货架冲床设备、槽钢冲床设备源头厂家排名

2026年制造业自动化升级浪潮下,货架冲床设备与槽钢冲床设备已成为金属加工企业提升生产效率、保障产品精度的核心硬件支撑。无论是货架立柱的批量冲孔、槽钢构件的精准加工,还是多型材适配的柔性生产,优质设备厂家的…

并发 - 分布式锁 (Distributed Lock) vs 本地锁 (Synchronized)

Java 并发进阶:分布式锁 (Distributed Lock) vs 本地锁 (Synchronized) 1. 什么是分布式锁? 在微服务或分布式系统环境中,当系统由多个独立的进程或节点组成时,如果这些不同的进程需要协调对同一个共享资源(如数据…

midscene.js简介

相关资料 官方网站 项目主页与文档:https://midscenejs.com MidScene 框架的官方文档站点提供了完整的开发资源,采用清晰的层级结构设计,包含以下核心内容: 快速入门指南 环境要求:Node.js 12+、现代浏览器支持说明 安装教程:npm/yarn安装命令及常见问题排查 第一个示例…

GPEN影视后期预研案例:老旧胶片数字修复流程探索

GPEN影视后期预研案例&#xff1a;老旧胶片数字修复流程探索 1. 引言&#xff1a;从老照片到高清人像的修复之旅 你有没有翻出过家里的老相册&#xff1f;泛黄的照片、模糊的脸庞、斑驳的划痕——这些承载记忆的影像&#xff0c;往往因为年代久远而失去了原本的模样。在影视后…

GPEN前端框架分析:Vue/React技术栈可能性推断

GPEN前端框架分析&#xff1a;Vue/React技术栈可能性推断 1. 引言&#xff1a;从功能界面反推技术选型逻辑 GPEN 图像肖像增强项目作为一个面向用户的 WebUI 工具&#xff0c;其前端呈现出高度结构化、组件化和交互丰富的特点。通过观察其实际运行效果与用户手册中描述的界面…

又是新的一天

今天对面工位的同事又在面试新员工,关系型数据库常用的函数,svn是如何避免代码提交冲突的。前台跨域问题。想起来自己面对面试的时候,也是什么也不懂。 今天开发,自己又学会了序列,CTE预加载技术。以前三五天才能…

Open-AutoGLM新闻阅读助手:热点资讯推送执行部署案例

Open-AutoGLM新闻阅读助手&#xff1a;热点资讯推送执行部署案例 1. 引言&#xff1a;让AI帮你刷手机&#xff0c;真正实现“动口不动手” 你有没有这样的经历&#xff1a;看到朋友分享的某个博主内容很感兴趣&#xff0c;立刻想打开抖音去搜、关注&#xff0c;但一连串点击操…

【稀缺技术曝光】:大型系统中MCP服务器动态资源配置的黄金法则

第一章&#xff1a;MCP服务器动态资源配置概述 在现代云计算与微服务架构中&#xff0c;MCP&#xff08;Microservice Control Plane&#xff09;服务器承担着服务发现、流量调度与资源协调的核心职责。面对业务负载的波动性&#xff0c;静态资源配置已无法满足高效运维的需求。…

2026年济南雅思培训机构推荐及综合参考

济南作为山东省教育资源集中地,雅思培训市场近年来呈现多元化发展态势,各类机构依托不同教学特色服务于广大学习者。了解当地机构的实际情况,有助于更好地匹配学习需求。一、推荐榜单推荐 [序号1]:超级学长推荐指数…

上海拆除公司、专业拆除公司、写字楼拆除公司、办公室拆除公司、商场拆除公司、室内拆除公司、室外拆除公司、工程拆除公司选择指南

2026上海酒店行业翻新拆除白皮书——专业室内拆除解决方案近年来,上海酒店行业进入存量更新密集期。据上海旅游行业协会数据,2026年上海中高端酒店翻新比例达62%,其中85%的酒店将“拆除环节的专业性”列为翻新前三大…

2026年冷干机大型厂家排名,哪家性价比高值得选购?

在工业生产与矿山作业的压缩空气处理领域,冷干机作为保障气源洁净干燥的核心设备,直接影响着后端设备的使用寿命与生产效率。面对市场上鱼龙混杂的冷干机大型厂家、冷干机资深厂商及冷干机服务商,企业如何精准选择既…

20260121给荣品RD-RK3588开发板的荣品Android13打包APK的时候出现问题3797897216 > 3263168512

Z:\rk-android13-20250818\device\rockchip\common\build\rockchip\Partitions.mk #BOARD_SUPER_PARTITION_SIZE ? 3263168512 BOARD_SUPER_PARTITION_SIZE ? 4294967296 20260121给荣品RD-RK3588开发板的荣品Android13打包APK的时候出现问题3797897216 > 3…