如何使用Python的__get__实现自定义描述符(Descriptors)逻辑?

千晨君_6046

千晨君_6046

2026-07-29

364人浏览

原创

__get__ 方法必须在 instance is none 时返回 self,否则类访问失效;仅实现 __get__ 为非数据描述符,赋值后不再触发;避免共享状态,应使用 weakkeydictionary 等按实例隔离缓存。

如何使用python的__get__实现自定义描述符(descriptors)逻辑?

__get__ 方法该返回什么才不会出错?

描述符的 <strong>get</strong> 方法被调用时,Python 会传入三个参数:self(描述符实例)、instance(访问该属性的实例对象)、owner(实例所属的类)。关键点在于:当 instance 为 None(即通过类而非实例访问属性),应返回描述符自身,否则可能触发 AttributeError 或静默失效。

  • 如果返回 None 或固定值而忽略 instance 状态,类属性访问会错误地返回实例级结果
  • 忘记处理 instance is None 场景,会导致 MyClass.attr 返回 None 而不是描述符对象,后续无法正常工作
  • 不要直接返回 self 以外的可变对象(如字典),除非你明确控制其生命周期,否则多个实例会共享同一份数据
class NonDataDescriptor:
    def __get__(self, instance, owner):
        if instance is None:
            return self  # 必须返回 self,否则类访问失效
        return f"from {instance.name}"

什么时候必须同时实现 __set__ 才能用 __get__?

<strong>get</strong> 单独存在时,描述符属于“非数据描述符”(non-data descriptor)。它只在实例字典中没有同名属性时才被触发。一旦你在实例上赋值(比如 obj.attr = 123),该值就会直接写入 obj.<strong>dict</strong>,后续再读取就绕过 <strong>get</strong>。

  • 想让 <strong>get</strong> 始终生效(比如做动态计算、权限校验),必须加上 <strong>set</strong>(哪怕只是抛错),变成“数据描述符”
  • 只实现 <strong>get</strong> 的常见用途是方法绑定、类级别的懒加载(如 @classmethod 底层就是靠这个机制)
  • 若误加了空的 <strong>set</strong>(self, instance, value): pass,反而会屏蔽实例字典赋值,导致所有写操作静默失败
class ReadOnlyDescriptor:
    def __get__(self, instance, owner):
        return instance._value * 2
    def __set__(self, instance, value):
        raise AttributeError("Read-only attribute")

如何避免 __get__ 中的 self 属性被多个实例污染?

描述符实例是类级别共享的,但它的状态(如 self.cache)会被所有拥有该描述符的实例共用。这不是 bug,而是设计特性——但容易被当成 bug。

Li Python Sec Check
Li Python Sec Check

Python 安全规范检查工具:基于 CloudBase 规范、腾讯安全指南,LLM 智能分析(默认禁用,优先本地执行)

下载
  • 不要在描述符里存实例相关数据(如 self.last_accessed),除非你用 weakref.WeakKeyDictionary 映射到具体实例
  • 常见错误:在 <strong>get</strong> 里缓存结果到 self._cache = {...},结果 A 实例改了,B 实例读到脏数据
  • 正确做法是把状态存在 instance.<strong>dict</strong>(需确保不冲突)或用外部映射结构
from weakref import WeakKeyDictionary
<p>class CachedProperty:
def <strong>init</strong>(self, func):
self.func = func
self.cache = WeakKeyDictionary()  # 按实例隔离
def <strong>get</strong>(self, instance, owner):
if instance is None:
return self
if instance not in self.cache:
self.cache[instance] = self.func(instance)
return self.cache[instance]</p>

__get__ 触发时机和性能陷阱

<strong>get</strong> 在每次属性访问时都执行,包括 hasattr()、getattr() 和点号访问。它不是惰性初始化,也不是装饰器式的一次性计算。

  • 频繁调用的属性(如循环体内)若在 <strong>get</strong> 中做耗时操作(IO、复杂计算),会显著拖慢性能
  • hasattr(obj, 'attr') 也会触发 <strong>get</strong>,如果里面抛异常(比如连接数据库失败),hasattr 就返回 False —— 这常被误认为“属性不存在”,其实是运行时报错
  • 不要用 <strong>get</strong> 做副作用操作(如发日志、改全局状态),因为调用时机不可控,且可能被优化掉(如某些 IDE 的代码分析)

描述符逻辑越简单越好;复杂逻辑建议移到单独方法里,由描述符委托调用。真正难的是权衡:既要利用描述符的自动触发能力,又要守住边界,不让它变成隐式副作用的温床。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1651

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4084

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1649

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

23597

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2887

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2927

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1143

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2263

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程