当前位置: 首页 > news >正文

Python全栈修炼之路 | 第15篇 :描述符与属性访问控制

本文是《Python全栈修炼之路》系列的第15篇,属于进阶修炼篇前半部分。适合已掌握Python基础语法,希望深入理解Python核心机制的读者。


前言

描述符(Descriptor)是Python中一个强大但常被忽视的特性。它是实现propertyclassmethodstaticmethod以及ORM框架的底层机制。理解描述符,才能真正理解Python的属性访问控制。

本文将深入探讨描述符协议、属性查找机制,并通过实战项目展示描述符的强大功能。


一、知识点讲解

1.1 什么是描述符

描述符是实现了描述符协议的类,即实现了以下一个或多个特殊方法:

  • __get__(self, obj, objtype=None):获取属性值
  • __set__(self, obj, value):设置属性值
  • __delete__(self, obj):删除属性
classDescriptor:"""最简单的描述符示例"""def__get__(self,obj,objtype=None):print(f"__get__ 被调用: obj={obj}, objtype={objtype}")return"描述符值"def__set__(self,obj,value):print(f"__set__ 被调用: obj={obj}, value={value}")def__delete__(self,obj):print(f"__delete__ 被调用: obj={obj}")classMyClass:attr=Descriptor()# 类属性是描述符实例obj=MyClass()# 访问属性print(obj.attr)# 调用 __get__# 设置属性obj.attr=100# 调用 __set__# 删除属性delobj.attr# 调用 __delete__

1.2 数据描述符 vs 非数据描述符

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

类型实现方法优先级示例
数据描述符__get__+__set__property(带setter)
非数据描述符__get__property(仅getter)、classmethodstaticmethod

优先级差异示例:

classDataDescriptor:"""数据描述符"""def__get__(self,obj,objtype=None):return"数据描述符的值"def__set__(self,obj,value):print(f"数据描述符阻止设置:{value}")classNonDataDescriptor:"""非数据描述符"""def__get__(self,obj,objtype=None):return"非数据描述符的值"classMyClass:data_attr=DataDescriptor()non_data_attr=NonDataDescriptor()obj=MyClass()# 数据描述符优先级高于实例属性obj.data_attr="新值"# 调用 __set__,实例属性不会被创建print(obj.data_attr)# "数据描述符的值"print(obj.__dict__)# {}(没有data_attr)# 非数据描述符优先级低于实例属性print(obj.non_data_attr)# "非数据描述符的值"obj.non_data_attr="实例属性值"# 创建实例属性print(obj.non_data_attr)# "实例属性值"(实例属性覆盖了描述符)print(obj.__dict__)# {'non_data_attr': '实例属性值'}

1.3 描述符方法详解

__get__(self, obj, objtype=None)
classTypedAttribute:"""类型检查描述符"""def__init__(self,name,expected_type):self.name=name self.expected_type=expected_type self.private_name=f"_{name}"def__get__(self,obj,objtype=None):ifobjisNone:# 通过类访问时,返回描述符自身returnselfreturngetattr(obj,self.private_name,None)def__set__(self,obj,value):ifnotisinstance(value,self.expected_type):raiseTypeError(f"{self.name}必须是{self.expected_type.__name__}类型,"f"而不是{type(value).__name__}")setattr(obj,self.private_name,value)classPerson:name=TypedAttribute("name",str)age=TypedAttribute("age",int)def__init__(self,name,age):self.name=name self.age=age# 使用p=Person("Alice",25)print(p.name)# Alice# p.age = "25" # TypeError: age 必须是 int 类型,而不是 str
__set__(self, obj, value)
classValidatedAttribute:"""带验证的描述符"""def__init__(self,min_value=None,max_value=None):self.min_value=min_value self.max_value=max_value self.values={}# 使用字典存储,避免实例属性冲突def__set__(self,obj,value):ifself.min_valueisnotNoneandvalue<self.min_value:raiseValueError(f"值不能小于{self.min_value}")ifself.max_valueisnotNoneandvalue>self.max_value:raiseValueError(f"值不能大于{self.max_value}")self.values[id(obj)]=valuedef__get__(self,obj,objtype=None):ifobjisNone:returnselfreturnself.values.get(id(obj))classTemperature:celsius=ValidatedAttribute
http://www.gsyq.cn/news/1498263.html

相关文章:

  • 一文搞懂AI Agent面试:ReAct原理+工具调用+Multi-Agent源码分析
  • 厦门首饰雨季出手会被压价?解析潮湿环境下首饰折价原因 - 开心测评
  • 天津黄金大跳水 但也不能随便下车 收的顶透明交易远离回收套路 - 奢侈品回收评测
  • Pipfile完全指南:现代Python依赖管理的终极解决方案
  • app安全测试-服务端
  • pinche_xcx开源项目贡献指南:如何参与开发与提交PR
  • 广州哪家装修公司靠谱?装企最新深度测评 - 装修新知
  • Android Studio全版本下载及汉化包地址
  • Unity毛发系统完整指南:从零开始创建逼真头发效果
  • 智谱清言怎么转 PDF?借助 AI 导出鸭实现格式高效转换
  • 2026重庆名表回收战力TOP榜单:欧米茄积家横评,收的顶断层登顶 - 奢侈品回收测评
  • 如何参考广东PCBA工厂排名选厂?FIRES方法论给出标准方案 - 资讯纵览
  • 2026年待办清单软件推荐:哪款日程管理工具真正好用?
  • 成都西装定制权威指南:5 家顶级店铺深度测评 - 西装爱好者
  • GraphQL服务性能深度解析:Mercurius的3大优化策略与架构思考
  • 2026年上海酒店家具回收处理完全指南——找官方一站式回收商这样做最稳 - 年度推荐企业名录
  • PS5 NOR Modifier终极指南:修复PS5 NOR文件与UART通信的完整解决方案
  • 2026年室内淘气堡厂家推荐榜单:商场/儿童乐园/幼儿园/亲子主题乐园淘气堡品牌实力与性价比深度测评 - 品牌发掘
  • 2026成都奢侈品回收,溢价出手比价秘籍,5大渠道筛选 - 商业快讯早知道
  • 2026 无锡滨湖区黄金回收指南!小白避坑 + 5 家放心店排名 - 禹竞
  • 微信旧版本下载 | 微信历史版本大全:微信4.1.10 for Windows 官方安装包
  • 在PyCharm写Python字典:新手必避7大坑
  • Vue3+Vite实践 01
  • 2026年上海二手制冷设备回收指南:5大专业服务商深度横评 - 年度推荐企业名录
  • 展锐平台摄像头点亮bringup
  • 啶虫脒农药残留检测卡快速检测果蔬中的啶虫脒农药残留
  • 2026年钢丝绳厂家十大品牌榜单:吊装钢丝绳/进口德国迪帕钢丝绳/电梯钢丝绳/起重钢丝绳/船用钢丝绳/港口起重机与塔吊钢丝绳优质厂家推荐 - 品牌发掘
  • Qt + FFmpeg 实战:将音视频文件解码为 PCM 数据
  • 12.linux笔记:线程
  • 【资源下载】一款免费驱动,告别付费