类定义时先执行类体填充namespace,再由元类__new__创建类对象,接着__init__初始化;类__dict__随后被冻结为只读映射;实例化时才触发type.__call__→类__new__→类__init__链。

类定义触发元类的 `__new__` 和 `__init__`
当你写下 class MyClass: 并执行时,Python 并不是直接构造类对象,而是调用**元类(默认是 type)** 的 __new__ 方法来创建类对象。这一步真正生成了类这个“对象”本身(注意:类也是对象,是 type 的实例)。紧接着,元类的 __init__ 被调用,完成对类对象的初始化——比如设置 __name__、__dict__、继承关系等。
你可以通过自定义元类观察这一过程:
class MyMeta(type):
def __new__(cls, name, bases, namespace):
print(f"__new__ 创建类对象: {name}")
return super().__new__(cls, name, bases, namespace)
def __init__(cls, name, bases, namespace):
print(f"__init__ 初始化类: {name}")
super().__init__(name, bases, namespace)
<p>class A(metaclass=MyMeta):
pass</p><h1>输出:</h1><h1><strong>new</strong> 创建类对象: A</h1><h1><strong>init</strong> 初始化类: A</h1><p>类体执行填充命名空间,形成 `namespace` 字典
在调用元类 __new__ 之前,Python 会先执行类体中的代码(包括函数定义、变量赋值、装饰器等),并将所有顶层绑定收集到一个字典中,即 namespace。这个字典最终作为参数传给元类的 __new__。
立即学习“Python免费学习笔记(深入)”;
- 函数定义(如
def method(self):)会被编译为函数对象,存入namespace - 类变量(如
x = 1)直接写入namespace - 装饰器(如
@staticmethod)在类体执行阶段就已作用于函数,影响最终存入namespace的对象
注意:namespace 不包含从父类继承的属性,它是“干净”的、仅属于当前类的命名空间快照。
TAYGOD免费企业建站系统是一款开源的免费程序,您可以 TAYGOD免费企业建站系统ASP版是一款基于asp+access的免费开源建站系统。整套系统的设计构造,完全考虑中小企业类网站的功能要求,网站后台功能强大,管理简捷,支持模板机制,能够快速建立您的企业网站。 系统特性: 采用流行的asp+access设计,功能强,实用性高。 代码美工完全分离,维护更方便。 对运行环境要求低,基本上一般的
类对象生成后,`__dict__` 被冻结为只读映射
一旦类对象由 type.__new__ 创建完成,它的 __dict__ 属性就被设为一个特殊的只读映射(mappingproxy),用于对外暴露类的属性。这意味着你不能直接对 MyClass.__dict__['x'] = ... 赋值,但可以通过 MyClass.x = ... 或 setattr(MyClass, 'x', ...) 修改——这些操作会委托给类的 __setattribute__(实际由 type 实现),并同步更新底层命名空间和 __dict__ 视图。
这种设计保障了类结构的稳定性,同时支持动态属性修改。
实例化时才触发 `__call__` 链:`type.__call__` → `__new__` → `__init__`
类对象本身是 type 的实例,因此调用 MyClass() 实际触发的是 type.__call__。这个方法内部按序调度:
- 先调用
MyClass.__new__(若未定义则用object.__new__)分配实例内存 - 再调用
MyClass.__init__初始化该实例(传入 self 和其他参数)
注意:类的 __new__ 和 __init__ 是为**实例**服务的,与类创建过程中的元类 __new__/__init__ 完全不同,不要混淆二者所处的层级。









