Python 对象模型与属性访问机制
1. 引言
Python 的灵活性不仅体现在语法层面,更来源于其高度动态的对象模型与统一的属性访问机制。相比于仅停留在“如何使用类与对象”,深入理解其底层运行原理,对于掌握 Django、ORM 乃至框架设计具有重要意义。
本文将围绕两个核心问题展开:
- Python 对象是如何创建的?
- Python 属性是如何被访问和控制的?
2. Python 对象模型
-
类的本质
在 Python 中,类并不是一种特殊结构,而是一个普通对象,其创建由内置元类
type完成。class A: x = 10等价于:
A = type("A", (), {"x": 10})由此可以得到:
- 类是
type的实例 type本身也是type的实例(自举结构)
type(A) is type type(type) is type这一机制使 Python 具备极强的动态构造能力。
- 类是
-
对象创建流程
对象的创建本质上是对“类对象”的一次调用:
a = A()在 Python 内部,该过程并非简单实例化,而是经历如下调用链:
A() ↓ type.__call__(A) ↓ 1️⃣ 调用 A.__new__() → 创建实例对象 ↓ 2️⃣ 调用 A.__init__() → 初始化实例 ↓ 返回实例需要注意:
- 类之所以可以被调用,是因为其元类
type实现了__call__ __new__负责创建对象__init__负责初始化对象
在一般开发中无需直接操作
__call__,但该机制在元类与框架设计中具有重要作用。 - 类之所以可以被调用,是因为其元类
-
属性存储机制
Python 使用字典结构管理对象属性:
- 实例属性:
obj.__dict__ - 类属性:
class.__dict__
示例:
class A: x = 10 a = A()此时:
a.__dict__ # {} A.__dict__ # 包含 'x': 10当执行:
a.x = 20本质为:
a.__dict__['x'] = 20 - 实例属性:
-
属性查找规则
访问属性:
a.x默认查找顺序为:
1️⃣ 实例字典 obj.__dict__ 2️⃣ 类字典 class.__dict__ 3️⃣ 父类链(MRO)示例:
class A: x = 10 a = A() a.x = 20优先返回实例属性 20。
若执行:
del a.x则回退至类属性,返回 10。
3. 属性访问机制
-
统一入口:getattribute
在 Python 中,所有属性访问都会统一转化为:
a.x → a.__getattribute__("x")因此可以认为:
__getattribute__是属性访问的总入口示例:
class A: def __getattribute__(self, name): print("访问", name) return super().__getattribute__(name) -
兜底机制:getattr
当属性在正常查找流程中未找到时,Python 会触发:
__getattr__(self, name)示例:
class A: def __getattr__(self, name): return 999 a = A() a.x # 返回 999 -
属性访问完整流程
属性访问的完整流程如下:
a.x ↓ 1️⃣ 调用 __getattribute__("x")(必定执行) ↓ 2️⃣ 若查找成功 → 直接返回 ↓ 3️⃣ 若抛出 AttributeError ↓ 4️⃣ 调用 __getattr__("x")关键区别如下:
方法 执行时机 作用 __getattribute__必定执行 控制所有属性访问 __getattr__查找失败后 提供兜底逻辑 -
异常驱动机制
需要特别强调:
__getattr__的触发依赖于AttributeError例如:
def __getattribute__(self, name): return 100此时不会触发
__getattr__,因为属性访问并未失败。 -
方法访问的本质
在 Python 中,方法本质上也是属性:
self.__getattr__等价于:
self.__getattribute__("__getattr__")因此,在调试或日志中可能会看到:
访问 __getattr__ -
递归风险与正确写法
在重写
__getattribute__时,如果直接访问属性,容易导致无限递归:错误示例:
def __getattribute__(self, name): return self.x其执行过程为:
self.x → __getattribute__("x") → self.x → ...最终触发
RecursionError。正确写法应为:
return super().__getattribute__(name) -
调试环境的特殊行为
在调试工具(如 PyCharm Debug)中,可能出现如下输出:
访问 __class__ 访问 __class__ ...原因在于调试器会主动访问对象属性以获取类型与结构信息,例如:
obj.__class__这些访问同样会触发
__getattribute__。需要明确:
这些行为来源于调试工具,而非程序本身逻辑。
4. 整体模型总结
-
对象关系结构
type → 类 → 实例type负责创建类- 类负责创建实例
-
属性访问模型
a.x ↓ __getattribute__ ↓ (内部查找) obj.__dict__ class.__dict__ 父类链 ↓ 查找失败 → __getattr__
5. 工程意义
上述机制在实际工程中具有直接应用价值:
| 机制 | 应用场景 |
|---|---|
__getattribute__ |
日志系统、权限控制 |
__getattr__ |
安全访问、默认值处理 |
| 属性查找链 | ORM 字段解析 |
type / 元类 |
模型定义、自动注册 |
例如:
- Django ORM 的字段访问机制
- DRF 的序列化流程
- 权限控制与中间件设计
这些框架能力,本质上均建立在 Python 对象模型之上。
6. 总结
Python 的核心机制可以归纳为两部分:
对象如何被创建(type / __new__ / __init__)
属性如何被访问(__getattribute__ / __getattr__)
进一步抽象为:
Python = 对象模型 + 属性访问控制机制
理解这一点,意味着从“使用 Python”迈向“理解 Python”,也是深入框架源码与系统设计的关键一步。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)