你可能写过不少 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 的基础上加一层拦截。