Python中类的定义和内存加载过程

好的 👍 我来给你一个 详细但系统化 的总结,帮助你彻底搞清楚:

🧠 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)