Python中描述符protocol 描述符协议__get__和__set__实现原理

描述符是python中用于自定义属性访问行为的对象,其核心在于实现__get__、__set__和__delete__方法。1. __get__用于获取属性值,当访问属性时触发;2. __set__用于设置属性值,控制赋值过程;3. __delete__用于删除属性。描述符必须作为类属性存在才生效,且数据描述符(含__set__或__delete__)优先级高于实例字典。若将值存储在描述符自身,会导致所有实例共享该值,应避免此做法。掌握描述符机制有助于深入理解属性访问、装饰器及property等内置工具的实现原理,并可用于高级特性如类型检查和自动属性管理。

在Python中,描述符(Descriptor)是一种实现特定协议的对象,这个协议包含 __get____set____delete__ 方法。通过这些方法,我们可以自定义类属性的访问行为。理解描述符的工作机制,有助于更深入掌握属性访问、装饰器、以及像 property 这样的内置工具背后的原理。

描述符协议的基本结构

描述符的核心在于它定义了如何通过类或实例访问属性。一个对象只要实现了以下任意一个方法,就可以被称为描述符:

__get__(self, instance, owner):用于获取属性值。__set__(self, instance, value):用于设置属性值。__delete__(self, instance):用于删除属性。

这些方法中的参数含义如下:

self:描述符实例本身。instance:使用该描述符的类实例(如果是通过实例访问的话)。owner:使用该描述符的类(即实例所属的类)。

比如,当你访问 obj.attr 时,如果 attr 是一个描述符对象,那么实际上会调用它的 __get__ 方法。

立即学习“Python免费学习笔记(深入)”;

__get__ 的工作方式

当访问某个属性时,Python解释器会在类和实例的命名空间中查找该属性。如果找到的是一个实现了 __get__ 的对象,并且这个对象是“数据描述符”(有 __set____delete__)或者“非数据描述符”,那么就会触发 __get__ 方法。

举个例子:

class MyDescriptor:    def __get__(self, instance, owner):        print("Getting value")        return 42class MyClass:    attr = MyDescriptor()obj = MyClass()print(obj.attr)

输出为:

Getting value42

在这个例子中,访问 obj.attr 实际上调用了 MyDescriptor.__get__ 方法。这里的关键点是,描述符必须作为类属性存在于另一个类中才会生效,不能直接赋值给实例属性。

__set__ 的作用与限制

如果你希望描述符可以控制属性的赋值过程,就需要实现 __set__ 方法。这个方法会在你执行类似 obj.attr = value 的操作时被调用。

来看一个简单的实现:

class MyDescriptor:    def __get__(self, instance, owner):        print("Getting value")        return self.value    def __set__(self, instance, value):        print("Setting value")        self.value = valueclass MyClass:    attr = MyDescriptor()obj = MyClass()obj.attr = 100print(obj.attr)

输出:

Setting valueGetting value100

注意几点:

如果一个描述符没有实现 __set__,那它就是一个“非数据描述符”,这时候实例字典中可以直接覆盖这个属性。如果描述符同时实现了 __get____set__,它就是“数据描述符”,这时实例字典中的同名属性会被忽略。描述符的 __set__ 方法通常会把值保存在实例上而不是描述符自身,否则多个实例共享同一个值。

例如,在上面的例子中,如果我们想让每个 MyClass 实例都有自己的值,应该把值存在 instance 上:

def __set__(self, instance, value):    instance._value = valuedef __get__(self, instance, owner):    return instance._value

这样就能避免不同实例之间的值互相干扰。

常见误区与注意事项

使用描述符时有几个常见的坑需要注意:

不要把值存在描述符自己身上:这会导致所有使用该描述符的实例共享同一个值。确保描述符是类属性:如果不是放在类中而是赋值给实例,描述符不会起作用。区分数据描述符和非数据描述符:前者优先级高于实例字典,后者则相反。避免循环引用:在 __get____set__ 中不小心修改了自身属性,可能会导致无限递归。

基本上就这些内容了。描述符是Python底层机制的一部分,虽然不常用,但在实现高级特性如类型检查、自动属性管理等方面非常有用。掌握其原理,能让你写出更灵活、可控的类设计。

以上就是Python中描述符protocol 描述符协议__get__和__set__实现原理的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1362411.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 01:46:56
下一篇 2025年12月14日 01:47:04

相关推荐

发表回复

登录后才能评论
关注微信