直接回答:描述符是实现了 __get__/__set__/__delete__ 中任意方法的对象,当它作为类属性存在时,拦截实例的属性访问——obj.attr 实际调用 Class.attr.__get__(obj, Class)。这是 Python 属性访问的底层钩子,property(数据描述符)、classmethod、staticmethod、实例方法绑定全都是用它实现的:方法能拿到 self,本质是函数描述符的 __get__ 返回了绑定方法。
展开解析:理解优先级链:数据描述符(同时有 get 和 set)> 实例字典 > 非数据描述符(只有 get)> __getattr__ 兜底——这解释了为什么实例赋值 obj.x = 1 能遮蔽方法(方法是非数据描述符),却遮蔽不了 property。自定义描述符的典型用途是声明式校验与托管属性:Django/SQLAlchemy 的模型字段、类型校验库,都是把"每个字段的 get/set 逻辑"收敛到描述符类里,类定义即 schema。实践提醒:描述符定义在类上、被所有实例共享,千万别在描述符对象上存实例状态(要存用 instance.__dict__ 或 WeakKeyDictionary);3.6 的 __set_name__ 让描述符知道自己绑定的属性名,省掉了手工传名。掌握描述符等于拿到了理解 Python ORM 和框架魔法的钥匙。
追问方向:为什么实例方法访问是动态绑定而类方法访问直接返回函数?getattr 与 getattribute 的区别?slot 与描述符的关系?
(约 460 字)