Python描述符指南中exception raising placeholder的具体含义是什么
Python描述符文档中"exception raising placeholder"的准确含义
这个表述不是Python的专属语法术语,是指南作者用的通俗说法,拆开理解即可,同时要注意区分「成为数据描述符的判定规则」和「实现合规只读属性的规范要求」两个层面的边界:
- 所谓
placeholder(占位符),核心是指:Python判定一个描述符属于数据描述符的唯一标准,是该描述符类型是否实现了__set__()(或__delete__())方法,和方法内部的实现逻辑完全无关。你不需要为__set__()编写完整的属性赋值逻辑,只要把这个方法定义出来、占住__set__这个方法名的位置,它就会触发数据描述符的高查找优先级——不会被实例字典里的同名属性覆盖,这是实现只读属性必须的基础(如果不定义__set__,就是非数据描述符,实例上给同名属性赋值会直接在实例字典创建属性,把描述符的逻辑挡掉,根本做不到只读)。 - 所谓
exception raising(抛出异常),是指这个占位的__set__()方法不需要写赋值逻辑,唯一要做的就是在被调用时抛出异常——毕竟只读属性本来就不允许赋值操作,总不能写个空方法让赋值操作静默失效,那样用户给属性赋值时不会收到任何报错,会误以为赋值成功,属于非常反直觉的坏实现。
关于抛出异常的类型要求
两个场景的规则完全不一样,不要混为一谈:
- 如果只是满足「被识别为数据描述符」的要求:抛任意异常都可以。解释器在判定描述符类型时,只会检查方法是否存在,根本不会执行方法逻辑、也不会校验你抛的异常类型。哪怕你在
__set__里写raise ValueError("随便抛")甚至不符合规范的抛非异常对象,只要方法定义存在,它就是个数据描述符。 - 如果要实现符合Python通用语义、和内置行为一致的只读描述符:必须抛出
AttributeError。
这是Python全生态的统一约定:所有对不可访问/不可赋值的属性进行操作时,统一抛出AttributeError——不管是内置类型的只读属性,还是用@property装饰器定义的只读属性(没写setter时被赋值),抛的都是这个异常。如果抛其他类型的异常,调用方无法按照常规的属性操作错误逻辑做捕获处理,会破坏代码的行为一致性,属于不符合规范的实现。
标准实现示例
文档说的「抛异常的占位方法」,对应到代码里就是下面这种最简实现:
class ReadOnlyAttr: def __init__(self, stored_value): self._val = stored_value def __get__(self, instance, owner): # 类访问时返回描述符本身,实例访问时返回存储的值 return self if instance is None else self._val # 这就是文档说的exception raising placeholder:没有赋值逻辑,只做占位+抛合规异常 def __set__(self, instance, value): raise AttributeError("cannot modify read-only attribute")
内容的提问来源于stack exchange,提问作者bad_coder
相关产品推荐
相关产品推荐

