Python中类的定义和内存加载过程
已于 2025年10月09日 22:19 修改
访问次数:0
好的 👍 我来给你一个 详细但系统化 的总结,帮助你彻底搞清楚:
🧠 Python 类的属性(包括类变量、方法、特殊属性等)在什么时候被创建、加载到内存、存放到哪里、又如何被访问。
🧩 一、Python 执行类定义时到底发生了什么
假设我们写了:
class MyClass(BaseClass):
x = 10 # 类变量
y = [] # 类变量(可变对象)
def foo(self): # 实例方法
return self.x
@classmethod
def bar(cls): # 类方法
return cls.x
@staticmethod
def baz(): # 静态方法
return "Hello"
Python 执行这段代码的过程其实是:
🔹 第一步:创建类定义的命名空间(一个临时字典)
当解释器读到 class MyClass: 时,会创建一个新的字典:
namespace = {}
接下来,它会在这个命名空间中执行类体里的所有语句。
🔹 第二步:执行类体内的代码
这一阶段 Python 实际上是“运行”类体中的语句,而不仅仅是“读取”。
执行顺序大概是:
| 类体代码 | 执行结果 | 存放在命名空间中 |
|---|---|---|
x = 10 | 创建整型对象 10 | 'x': 10 |
y = [] | 创建空列表对象 | 'y': [] |
def foo(self): ... | 创建函数对象 | 'foo': <function foo> |
@classmethod def bar(cls): ... | 创建函数对象,然后被装饰为 classmethod 对象 | 'bar': <classmethod object> |
@staticmethod def baz(): ... | 创建函数对象,然后被装饰为 staticmethod 对象 | 'baz': <staticmethod object> |
执行完毕后,这个命名空间看起来像这样:
namespace = {
'x': 10,
'y': [],
'foo': <function foo>,
'bar': <classmethod object>,
'baz': <staticmethod object>,
}
🔹 第三步:调用 type() 创建类对象
执行完类体后,Python 会隐式地调用:
MyClass = type('MyClass', (BaseClass,), namespace)
也就是说:
- type() 是类的“工厂函数”;
- 它把类名、父类、以及刚刚执行完的命名空间,打包生成一个新的 类对象(class object);
- 然后绑定到当前作用域的名字 MyClass 上。
这时,类对象就正式创建完毕,并被加载到内存中。
🧠 二、类创建后在内存中的结构
创建完成后,在内存中你可以这样理解:
┌────────────────────────────────────────┐
│ type(元类,所有类的类) │
└──────────────┬─────────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ MyClass(类对象) │
│ ├── __name__ = 'MyClass' │
│ ├── __bases__ = (BaseClass,) │
│ ├── __dict__ = { │
│ │ 'x': 10, │
│ │ 'y': [], │
│ │ 'foo': <function foo>, │
│ │ 'bar': <classmethod object>, │
│ │ 'baz': <staticmethod object>, │
│ │ '__module__': '__main__', │
│ │ '__doc__': None, │
│ │ ... │
│ │ } │
└────────────────────────────────────────┘
│
▼
┌──────────────┐
│ 实例对象 a │
│ ├── __dict__ │
│ │ {'z': 5} │
│ └── ... │
└──────────────┘
⚙️ 三、不同属性的加载与存储时机
| 属性类型 | 创建时机 | 存储位置 | 是否被所有实例共享 | 自动加载? |
|---|---|---|---|---|
| 类变量 | 类体执行时 | 类的 __dict__ | ✅ 是 | ✅ |
| 实例方法 | 类体执行时 | 类的 __dict__ | ✅ 是 | ✅ |
类方法 (@classmethod) | 类体执行时 | 类的 __dict__ | ✅ 是 | ✅ |
静态方法 (@staticmethod) | 类体执行时 | 类的 __dict__ | ✅ 是 | ✅ |
特殊属性 (__name__, __dict__, __bases__, __module__, 等) | type() 创建类对象时自动生成 | 类对象 | ✅ 是 | ✅ |
| 实例变量 | 实例化(__init__ 执行)时 | 实例的 __dict__ | ❌ 否 | ❌(需手动创建) |
🔍 四、属性访问的查找顺序
Python 的属性查找顺序(MRO:方法解析顺序)如下:
实例对象 → 类对象 → 父类 → 祖先类 → object
举例:
class A:
x = 1
class B(A):
pass
b = B()
访问:
b.x
查找路径:
1️⃣ b.__dict__ 中有没有 x?
2️⃣ 没有 → 去 B.__dict__ 查找;
3️⃣ 没有 → 去 A.__dict__ 查找;
4️⃣ 如果都没有,去 object 查找。
5️⃣ 如果仍没有,触发 AttributeError。
🧩 五、方法绑定机制(动态绑定)
方法其实只是类属性(函数对象),但 Python 在访问它们时会自动绑定:
| 方法类型 | 调用方式 | 自动传入的第一个参数 |
|---|---|---|
| 实例方法 | obj.method() | self(实例) |
| 类方法 | MyClass.method() 或 obj.method() | cls(类) |
| 静态方法 | MyClass.method() 或 obj.method() | ❌ 无自动绑定 |
绑定是在访问属性(即 obj.method)的那一刻动态发生的,而不是类定义时。
🧩 六、特殊属性的生成
当类对象创建完成后,Python 会自动给它添加一些标准属性:
| 属性名 | 含义 |
|---|---|
__name__ | 类名字符串 |
__qualname__ | 完整限定名(含嵌套类路径) |
__module__ | 所在模块名 |
__bases__ | 父类元组 |
__dict__ | 类属性字典(不可写的 mappingproxy) |
__doc__ | 文档字符串 |
这些都是在调用 type() 创建类对象时自动生成的,不需用户定义。
✅ 七、整体总结(一句话版)
当 Python 执行类定义时,它立即执行类体代码,生成类变量、方法、类方法和静态方法,并调用 type() 创建类对象,将这些属性加载到内存;而实例变量只会在实例化(__init__)时才创建。
评论(0)