当前位置: 首页 > 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.jsqmd.com/news/986517/

相关文章:

  • 厦门首饰雨季出手会被压价?解析潮湿环境下首饰折价原因 - 开心测评
  • 一文搞懂AI Agent面试:ReAct原理+工具调用+Multi-Agent源码分析
  • Pipfile完全指南:现代Python依赖管理的终极解决方案
  • 天津黄金大跳水 但也不能随便下车 收的顶透明交易远离回收套路 - 奢侈品回收评测
  • app安全测试-服务端
  • 产业从业者必看|国内外知名半导体行业博览会推荐清单 - 品牌2026
  • 2026湖北荆门市正规靠谱的8大封闭式戒网瘾特训学校排名,专治青春期叛逆、厌学、沉迷手机 - 辛云教育资讯
  • PyOWM社区贡献指南:如何参与这个开源天气库的开发
  • 2026 北京耀辉:深耕 35 载,铸就黄金奢侈品回收行业标杆 - 奢侈品回收
  • npx skills终极指南:3种使用场景+5大进阶技巧让AI技能管理效率翻倍
  • 广州LV回收哪家最划算?6大平台实测性价比排名出炉 - 薛定谔的梨花猫
  • Android Studio全版本下载及汉化包地址
  • 广州哪家装修公司靠谱?装企最新深度测评 - 装修新知
  • pinche_xcx开源项目贡献指南:如何参与开发与提交PR
  • 如何用99个公共Tracker服务器打造极速BT下载网络:Trackerslist完整指南
  • 2026年日照短视频获客与AI GEO优化:实体店老板必看的5大服务商深度评测 - 企业名录优选推荐
  • LangChain4j终极指南:如何让AI成为你的SQL数据库翻译官
  • 无锁队列的设计
  • 兰州安宁区卖黄金实测:上门回收的水有多深?我把5家都试了一遍 - 奢佳美黄金珠宝
  • 天津卖黄金选本地门店 收的顶专业回收 透明交易远离回收套路 - 奢侈品回收评测
  • Unity毛发系统完整指南:从零开始创建逼真头发效果
  • 163MusicLyrics:跨平台音乐歌词提取与处理工具全解析
  • flask:sqlalchemy:指向值为null
  • 2026四川成都定制游怎么选导游|TOP8纯玩路线与熊猫+火锅+宽窄巷子体验解 - 随峰国旅
  • AI 编程时代,为什么脚手架依然不可替代?
  • 2026年上海搬家公司大盘解析 传统搬家套路梳理与日式一站式服务全面对比 - 信息热点
  • 智谱清言怎么转 PDF?借助 AI 导出鸭实现格式高效转换
  • 以正道致长远:重塑教培行业良性竞争生态 - 速递信息
  • 2026贵阳中考高考志愿填报机构怎么选?体制内就业破局指南 - 年度推荐企业名录
  • 珠海香洲区黄金回收行情与六家正规机构深度对比 - 上门黄金回收