Fluent-Python-第20章:属性描述符
属性描述符
学会描述符之后,不仅有更多的工具集可用,还会对 Python 的运作方式有更深入的理解,并由衷赞叹 Python 设计的优雅。
——Raymond Hettinger, Python 核心开发者和专家
本章的话题是描述符。
描述符是实现了特定协议的类,这个协议包括 __get__
、__set__
、和 __delete__
方法。
有了它,我们就可以在类上定义一个托管属性,并把所有对实例中托管属性的读写操作交给描述符类去处理。
# 描述符示例:将一个属性托管给一个描述符类
class CharField: # 描述符类
def __init__(self, field_name):
self.field_name = field_name
def __get__(self, instance, storage_cls):
print('__get__', instance, storage_cls)
if instance is None: # 直接在类上访问托管属性时,instance 为 None
return self
return instance[self.field_name]
def __set__(self, instance, value):
print('__set__', instance, value)
if not isinstance(value, str):
raise TypeError('Value should be string')
instance[self.field_name] = value
class SomeModel: # 托管类
name = CharField('name') # 描述符实例,也是托管类中的托管属性
def __init__(self, **kwargs):
self._dict = kwargs # 出巡属性,用于存储属性
def __getitem__(self, item):
return self._dict[item]
def __setitem__(self, item, value):
self._dict[item] = value
print(SomeModel.name)
d = SomeModel(name='some name')
print(d.name)
d.name = 'another name'
print(d.name)
try:
d.name = 1
except Exception as e:
print(repr(e))
__get__ None <class '__main__.SomeModel'>
<__main__.CharField object at 0x063AF1F0>
__get__ <__main__.SomeModel object at 0x063AF4B0> <class '__main__.SomeModel'>
some name
__set__ <__main__.SomeModel object at 0x063AF4B0> another name
__get__ <__main__.SomeModel object at 0x063AF4B0> <class '__main__.SomeModel'>
another name
__set__ <__main__.SomeModel object at 0x063AF4B0> 1
TypeError('Value should be string')
描述符的种类
根据描述符上实现的方法类型,我们可以把描述符分为覆盖型描述符和非覆盖型描述符。
实现 __set__
方法的描述符属于覆盖型描述符,因为虽然描述符是类属性,但是实现 __set__
方法的话,会覆盖对实例属性的赋值操作。
而没有实现 __set__
方法的描述符是非覆盖型描述符。对实例的托管属性赋值,则会覆盖掉原有的描述符属性,此后再访问该属性时,将不会触发描述符的 __get__
操作。如果想恢复原有的描述符行为,则需要用 del
把覆盖掉的属性删除。
具体可以看官方 Repo 的例子。
描述符的用法建议
- 如果只想实现一个只读描述符,可以考虑使用
property
而不是自己去实现描述符; - 只读描述符必须有
__set__
方法,在方法内抛出AttributeError
,防止属性在写时被覆盖; - 用于验证的描述符可以只有
__set__
方法:通过验证后,可以修改self.__dict__[key]
来将属性写入对象; - 仅有
__get__
方法的描述符可以实现高效缓存; - 非特殊的方法可以被实例属性覆盖。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异