当前位置:首页>python>Python 元类(上):类也是对象

Python 元类(上):类也是对象

  • 2026-10-11 07:40:46
Python 元类(上):类也是对象

你可能写过不少 Python 类了。定义一个类,创建实例,调用方法——这套流程你已经很熟了。

但你有没有想过一个问题:类本身,是谁创建的?

类,其实是一个对象

我们先做一个小实验:

class Dog:    species = "Canine"    def bark(self):        return "Woof!"print(type(Dog))  # <class 'type'>

type(Dog) 返回的不是 Dog 的实例类型,而是 Dog 这个类本身的类型。

你没看错——Dog 是一个对象。一个在运行时真实存在的、可以赋值、可以传递、可以放进列表的对象。

my_class = Dog            # 把类赋给变量print(my_class().bark())  # Woof!  完全正常

在大多数语言里,类是编译器用的蓝图,编译完就消失了。但 Python 不一样——类活在运行时里,它是一个实实在在的对象。

既然是对象,那它一定有某个东西创建了它。

type:Python 内置的类工厂

你大概用 type() 查过类型:

print(type(42))       # <class 'int'>print(type("hello"))  # <class 'str'>

但 type() 还有另一个身份——它能动态地创建一个类。调用方式是 type(类名, 父类元组, 属性字典):

# type(名称, 基类, 命名空间字典)Cat = type("Cat", (), {    "sound": "Meow!",    "speak": lambda self: self.sound})c = Cat()print(c.speak())  # Meow!print(type(Cat))  # <class 'type'>

这三个参数分别对应了类的三个核心要素:

参数
含义
成为类的哪个属性
name
类名
__name__
bases
父类元组
__bases__
dict
命名空间字典(属性和方法)
__dict__

来个带继承的:

class Animal:    def breathe(self):        return "breathing..."Dog2 = type("Dog2", (Animal,), {"bark": lambda self: "Woof!"})d = Dog2()print(d.breathe())           # breathing...  ← 继承的方法生效了print(isinstance(d, Animal))  # True          ← 继承关系也有了

所以结论很简单:你写的每一个 class 语句,底层都是 type() 在帮你创建类。

# 这两种写法完全等价# 写法 A:用 class 语句class MyClassA:    x = 10    def greet(self):        return "hello"# 写法 B:用 type() 动态创建MyClassB = type("MyClassA", (), {"x": 10, "greet": lambda self: "hello"})print(type(MyClassA) is type(MyClassB))  # True —— 它们都是 type 创建的

class 语句背后发生了什么?

当你写下 class Dog: 的时候,Python 实际上做了三件事:

第一步:在当前作用域中查找 metaclass 关键字参数。如果没有,就去父类里找——看看谁的 type() 最特殊。如果都没有,就用默认的 type。

第二步:调用 type.__new__(type, "Dog", (), namespace) 创建类对象。这里的 namespace 是类体中所有属性和方法组成的字典。

第三步:调用 type.__init__(dog_class, ...) 初始化类对象。

整个过程可以这样理解:

class Dog:              ← Python 看到这行    species = "Canine"  ← 执行类体,构建 namespace 字典    def bark(self):     ← 同上        return "Woof!"# 等价于:Dog = type("Dog", (), {"species": "Canine", "bark": ...})

type 就像一个工厂:你给它原材料(名字、父类、属性),它返回一个完整的类对象。

那 type 的类型又是什么?

既然 type 创建了所有类,那 type 自己呢?

print(type(type))  # <class 'type'>

type 的类型是它自己。这是一个自引用。

在 Python 的对象体系里,有一条贯穿始终的关系链:

type ──创建──→ 类(Dog、Cat)──创建──→ 实例(my_dog、my_cat)  ↑  └── type 的类型也是 type(自引用)

注意看:Dog 的实例是 my_dog,type 的实例是 Dog。类是元类的实例,就像对象是类的实例一样。

这里有一个关键的统一:在 Python 3 中,type 和 class 这两个概念已经合二为一了。一个对象的类型就是它的类,type(obj) 和 obj.__class__ 返回同一个东西。

Tim Peters(Python 之禅的作者)说过:「元类是比 99% 的用户需要担心的更深的魔法。如果你在犹豫是否需要元类,那你不需要。」

但理解它,能帮你理解 Python 对象模型的全貌。

Python 2 和 Python 3 的分岔路

如果你读过一些老代码或老教程,可能会看到这种写法:

# Python 2 的写法class MyClass:    __metaclass__ = SomeMeta

这是 Python 2 指定元类的方式——在类体里放一个 __metaclass__ 变量。

但在 Python 3 里,这行代码完全无效。Python 3 会默默忽略它,不会报错,也不会有任何效果:

# Python 3 中这样写,元类不会生效!class OldStyle:    __metaclass__ = type  # 被忽略print(type(OldStyle))  # <class 'type'> —— 还是默认的 type,没有别的print(hasattr(OldStyle, '_meta_version'))  # False —— 元类没起作用

Python 3 的正确写法是:

class MyClass(metaclass=SomeMeta):    pass

另外,Python 2 有两种类:旧式类(不继承 object)和新式类(显式继承 object)。旧式类不支持完整的元类机制,type() 返回的结果和 __class__ 不一致。Python 3 里没有这个区分——所有类都自动继承 object,都是新式类,type() 和 __class__ 始终一致。

这些差异在后面讲到具体写法时还会再提。现在你只需要记住:如果你在 Python 3 环境下,忘掉 __metaclass__,用 metaclass= 就对了。

为什么要了解这些?

你可能会想:我平时写业务代码,直接 class Foo: 就行了,为什么要关心 type?

因为理解了 type 是一个类工厂,你才能理解元类——元类本质上就是你自己写的类工厂。

而理解了元类,你才能看懂 Django Models、SQLAlchemy、DRF 这些框架到底在干什么——它们都在类定义的时候做了大量「魔法」,而这些魔法的底层就是元类。

下一篇,我们自己来写一个类工厂。 不难,就是在 type 的基础上加一层拦截。

最新文章

随机文章