目录
- 前言
- 一、基础概念
- [二、Python 属性两大查找链路](#二、Python 属性两大查找链路)
-
- [2.1 链路一:方法查找链(解释器级别)](#2.1 链路一:方法查找链(解释器级别))
- [2.2 链路二:业务属性查找链(方法内部级别)](#2.2 链路二:业务属性查找链(方法内部级别))
- [2.3 双链路执行顺序](#2.3 双链路执行顺序)
- 三、三大属性操作完整机制
- 四、描述符协议(底层扩展机制)
-
- [4.1 描述符分类](#4.1 描述符分类)
- [4.2 描述符介入后的执行规则](#4.2 描述符介入后的执行规则)
- [4.3 完整实战示例](#4.3 完整实战示例)
- 五、终极完整执行链路汇总
-
- [5.1 属性读取全链路](#5.1 属性读取全链路)
- [5.2 属性赋值全链路](#5.2 属性赋值全链路)
- [5.3 属性删除全链路](#5.3 属性删除全链路)
前言
属性操作是 Python 面向对象编程的核心基础。本文系统性梳理 Python 属性读写删三大内置函数、底层魔法方法、描述符协议的完整工作机制
一、基础概念
在 Python 中,一切皆对象,实例、类、模块、函数均支持属性操作。Python 为属性操作提供了三层标准化实现:
- 上层接口:
getattr()/setattr()/delattr()内置函数(安全操作属性) - 中间钩子:
__getattribute__/__setattr__/__delattr__/__getattr__魔法方法 - 底层协议:描述符协议(
__get__/__set__/__delete__)
二、Python 属性两大查找链路
2.1 链路一:方法查找链(解释器级别)
作用 :解释器寻找「属性操作的执行者」------ 底层魔法方法
触发时机 :每次执行属性读写删操作时,最先执行
查找规则:
- 针对当前对象的类,走 MRO 继承链(包含当前类)层层向上查找
- 中途任意父类重写了对应魔法方法,立即停止查找,执行当前类的重写方法
- 整条链路无重写,最终找到顶层基类 object 的原生魔法方法
2.2 链路二:业务属性查找链(方法内部级别)
作用 :魔法方法内部,寻找用户真正需要的「业务属性」(name/age/ 自定义方法)
触发时机 :解释器找到魔法方法后,方法内部执行
查找规则(实例属性)
- 查找类及其父类中的 数据描述符(
__delete__或__set__) - 其次:查找实例自身
__dict__ - 再次:查找非数据描述符、普通类属性
- 最后:沿着 MRO 查找父类
- 查找失败:抛出 AttributeError 异常
2.3 双链路执行顺序
- 先找方法:解释器通过 MRO 链,找到
__getattribute__执行者 - 再找属性:执行者内部,通过属性链找到目标业务属性
三、三大属性操作完整机制
3.1 获取属性
上层调用方式
语法糖:obj.属性名
内置函数:getattr(obj, name, default=None)
完整执行流程
- 解释器通过
MRO方法查找链 找到__getattribute__ - 执行
__getattribute__,按照业务属性查找链检索属性 - 查找成功:直接返回属性值
- 查找失败:抛出异常 → 触发
__getattr__兜底方法
底层原生伪源码(object 原生实现)
python
class object:
def __getattribute__(self, name: str):
"""
Python 官方正确版 __getattribute__ 实现
修复:数据描述符优先级 > 实例属性
"""
cls = type(self)
# ======================
# 第一步:最高优先级 → 查找【数据描述符】(类中定义)
# ======================
for base in cls.__mro__:
if name in base.__dict__:
attr = base.__dict__[name]
# 数据描述符:同时实现 __get__ 和 __set__
if hasattr(attr, "__set__") or hasattr(attr, "__delete__"):
if hasattr(attr, "__get__"):
return attr.__get__(self, cls)
# ======================
# 第二步:查找【实例自身属性】
# ======================
if name in self.__dict__:
return self.__dict__[name]
# ======================
# 第三步:查找【非数据描述符 / 普通类属性】
# ======================
for base in cls.__mro__:
if name in base.__dict__:
attr = base.__dict__[name]
if hasattr(attr, "__get__"):
return attr.__get__(self, cls)
return attr
# ======================
# 第四步:全部失败,抛错触发 __getattr__
# ======================
raise AttributeError(f"'{cls.__name__}' object has no attribute '{name}'")
兜底方法 getattr
仅在属性查找失败、抛异常后触发,用于自定义兜底逻辑,不会主动执行:
python
class Demo:
def __getattr__(self, name):
# 不存在的属性统一返回默认值
return None
obj = Demo()
print(obj.abc) # None
3.2 设置属性
上层调用方式
语法糖:obj.属性名 = 值
内置函数:setattr(obj, name, value)
完整执行流程
- 解释器通过 MRO 方法查找链 找到
__setattr__ - 执行底层赋值逻辑
- 优先判断:是否存在数据描述符,存在则执行描述符
__set__ - 无描述符:直接写入实例
__dict__
底层原生伪源码
python
class object:
def __setattr__(self, name: str, value):
cls = type(self)
# 1. 数据描述符优先级最高,优先执行
for base in cls.__mro__:
if name in base.__dict__:
attr = base.__dict__[name]
if hasattr(attr, "__set__"):
attr.__set__(self, value)
return
# 2. 无描述符,写入实例字典
self.__dict__[name] = value
3.3 删除属性
上层调用方式
语法糖:del obj.属性名
内置函数:delattr(obj, name)
完整执行流程
- 解释器通过 MRO 方法查找链 找到
__delattr__ - 优先判断:是否存在带
__delete__的数据描述符 - 存在则执行描述符删除逻辑
- 不存在则直接删除实例
__dict__中的属性
底层原生伪源码
python
class object:
def __delattr__(self, name: str):
cls = type(self)
# 1. 优先执行数据描述符 __delete__
for base in cls.__mro__:
if name in base.__dict__:
attr = base.__dict__[name]
if hasattr(attr, "__delete__"):
attr.__delete__(self)
return
# 2. 删除实例属性
if name in self.__dict__:
del self.__dict__[name]
else:
raise AttributeError()
3.4 检查属性
上层调用方式
语法:hasattr(obj, name: str) -> bool
作用:安全判断对象是否包含指定属性,返回布尔值
完整执行流程
- 底层调用
getattr(obj, name)尝试获取属性 - 属性获取成功 → 返回 True
- 抛出
AttributeError→ 返回 False - 会完整触发
__getattribute__ 和 __getattr__逻辑
底层原生伪源码
python
def hasattr(obj, name: str) -> bool:
"""
hasattr 官方等效实现
本质:封装 getattr,捕获异常
"""
try:
getattr(obj, name)
return True
except AttributeError:
return False
四、描述符协议(底层扩展机制)
描述符是 Python 实现属性拦截、校验、托管的底层协议,property、staticmethod 均基于描述符实现。
4.1 描述符分类
数据描述符(Data Descriptor)
实现了 __set__ 或 __delete__ 任意一个方法 → 就是数据描述符(不需要 __get__)
非数据描述符(Non-data Descriptor)
仅实现 __get__,没有 __set__ / __delete__
4.2 描述符介入后的执行规则
描述符逻辑嵌入在 __getattribute__ / __setattr__ / __delattr__ 内部,优先级高于普通属性,会重写默认属性行为。
4.3 完整实战示例
python
# 自定义数据描述符
class FieldDescriptor:
def __get__(self, instance, owner):
# self:描述符实例自身
# instance:被代理对象
# 被代理对象的类
print("执行描述符读取 __get__")
return self.val
def __set__(self, instance, value):
print("执行描述符赋值 __set__")
self.val = value
class User:
# 绑定描述符
age = FieldDescriptor()
obj = User()
obj.age = 18 # 触发描述符 __set__
print(obj.age) # 触发描述符 __get__
五、终极完整执行链路汇总
5.1 属性读取全链路
- 执行
obj.name / getattr(obj, "name") - 解释器 MRO 查找
__getattribute__(重写优先,最终兜底 object) - 执行
__getattribute__,内部检索业务属性 - 描述符 → 实例属性→类属性 → 父类属性
- 查找失败抛错 → 触发
__getattr__兜底
5.2 属性赋值全链路
- 执行
obj.name = val / setattr(obj, "name", val) - 解释器 MRO 查找
__setattr__ - 优先执行数据描述符
__set__ - 无描述符则写入实例
__dict__
5.3 属性删除全链路
- 执行
del obj.name / delattr(obj, "name") - 解释器 MRO 查找
__delattr__ - 优先执行描述符
__delete__ - 无描述符则删除实例属性