文章目录
- [1. `type`](#1.
type
) - [2. 元类定义与使用](#2. 元类定义与使用)
-
- [2.1. 定义元类(继承自`type`)](#2.1. 定义元类(继承自
type
)) - [2.2. 指定目标类使用元类(`metaclass`参数)](#2.2. 指定目标类使用元类(
metaclass
参数)) - [2.3. "继承元类" vs "指定元类"](#2.3. “继承元类” vs “指定元类”)
- [2.1. 定义元类(继承自`type`)](#2.1. 定义元类(继承自
- [3. 元类核心方法](#3. 元类核心方法)
-
- [3.1. `new`](#3.1.
__new__
) - [3.2. `init`](#3.2.
__init__
) - [3.3. `call`](#3.3.
__call__
)
- [3.1. `new`](#3.1.
- [4. 应用场景](#4. 应用场景)
- [5. `super`调用](#5.
super
调用) - [6. 总结](#6. 总结)
本文参考视频链接:
元类(Metaclass)是"创建类的类",用于自定义类的创建流程。
要理解元类,必须先回顾Python中"类的默认创建方式"------所有普通类(如class A:
)的底层都是由type
(Python内置元类)创建的。元类的本质就是替换默认的type
,自定义类的创建逻辑。
1. type
type
是Python的"内置元类",所有普通类都是type
的实例(即"类是元类的对象")。
静态定义类(class A:
)与动态调用type
创建类完全等价 ,type
是默认的"类的创建者"(即内置元类)。
python
# 1. 静态定义类A
class A:
name = "AAA"
def F(self):
print(1)
# 2. 动态调用type创建类A(与上述静态定义完全等价)
def F(self):
print(1)
A = type(
"A", # 类名(字符串)
(), # 父类元组(无父类时为空)
{"name": "AAA", "F": F} # 类属性/方法字典
)
元类的核心是"自定义类的创建逻辑 "------当我们不想用默认的type
创建类时,可以定义一个继承自type
的类(即元类),并指定目标类由这个元类创建。
元类的本质关系:实例 → 类 → 元类
Python中存在三层层级关系,这是理解元类的关键:
层级 | 角色 | 示例 | 关系描述 |
---|---|---|---|
第1层 | 实例(Object) | o = A() 中的o |
o 是A (类)的实例 |
第2层 | 类(Class) | class A: 中的A |
A 是M (元类)的实例 |
第3层 | 元类(Metaclass) | class M(type): 中的M |
M 继承自type ,是"创建类的类" |
小结:
- 实例由类创建(
o = A()
); - 类由元类创建(
A = M(...)
,默认M
是type
)。
2. 元类定义与使用
2.1. 定义元类(继承自type
)
元类必须继承自type
(因为type
是所有元类的"基类"),通过重载type
的方法(如__new__
、__init__
)实现自定义逻辑。
python
# 定义元类M,继承自type
class M(type):
# 重载__new__方法:在类创建前执行,负责创建类对象
def __new__(cls, name, bases, attrs):
# cls:元类本身(即M)
# name:目标类的类名(如"A")
# bases:目标类的父类元组(如())
# attrs:目标类的属性/方法字典(如{"name": "AAA", "F": F})
print(f"类名:{name}")
print(f"父类:{bases}")
print(f"类属性:{attrs}")
# 调用父类(type)的__new__,最终创建并返回类对象
return super().__new__(cls, name, bases, attrs)
2.2. 指定目标类使用元类(metaclass
参数)
通过在类定义时添加metaclass
参数,指定该类由自定义元类(如M
)创建,而非默认的type
。
python
# 定义类A,指定元类为M(而非默认的type)
# 注意:不是"A继承M",而是"A由M创建"
class A(metaclass=M):
name = "AAA"
def F(self):
print(1)
运行上述代码时,无需创建A的实例,就会打印以下内容:
类名:A
父类:()
类属性:{'__module__': '__main__', '__qualname__': 'A', 'name': 'AAA', 'F': <function A.F at 0x...>}
结论:元类的__new__
方法在目标类定义时自动调用(而非实例化时),负责创建类对象。
2.3. "继承元类" vs "指定元类"
"类继承元类"和"类指定元类"两者本质不同:
写法 | 含义 | 结果 |
---|---|---|
class A(M): |
A继承M(M是普通类) | A是M的子类,A的元类仍是默认的type |
class A(metaclass=M): |
A由M创建(M是元类,继承自type) | A是M的实例,A的元类是M |
验证方式:查看类的元类(type(A)
)
python
class M(type):
pass
class A(metaclass=M):
pass
class B(M): # B继承M(M是元类,但B的元类仍是type)
pass
print(type(A)) # 输出:<class '__main__.M'>(A的元类是M)
print(type(B)) # 输出:<class 'type'>(B的元类是默认的type)
3. 元类核心方法
3.1. __new__
- 调用时机 :目标类(如A)定义时,元类首先调用
__new__
; - 核心作用:创建类对象(即最终的A),可以在创建前修改类的属性/方法(如过滤非法属性);
- 参数含义 :
cls
:元类本身(如M);name
:目标类名(如"A");bases
:目标类的父类元组;attrs
:目标类的属性/方法字典;
- 返回值 :必须返回调用父类
__new__
创建的类对象(如super().__new__(cls, name, bases, attrs)
)。
例如:过滤类中的非法方法,禁止类中出现test_
开头的方法,否则报错。
python
class M(type):
def __new__(cls, name, bases, attrs):
# 遍历类的所有属性/方法
for attr_name, attr_value in attrs.items():
# 判断是否是test_开头的函数
if attr_name.startswith("test_") and callable(attr_value):
raise TypeError(f"类{A}中禁止定义test_开头的方法:{attr_name}")
# 创建并返回类对象
return super().__new__(cls, name, bases, attrs)
# 测试:定义含test_方法的类,触发报错
class A(metaclass=M):
def test_func(self): # 非法方法
pass
# 运行结果:TypeError: 类A中禁止定义test_开头的方法:test_func

3.2. __init__
- 调用时机 :
__new__
创建类对象后,元类自动调用__init__
; - 核心作用:初始化已创建的类对象(如给类添加额外属性),此时类对象已存在;
- 参数含义 :
cls
:元类本身(如M);name
:目标类名(如"A");bases
:目标类的父类元组;attrs
:目标类的属性/方法字典;
- 返回值:无需返回(或返回None),仅负责初始化。
例如:创建类时,自动给类添加random_id
属性(0-100的随机数)。
python
import random
class M(type):
def __new__(cls, name, bases, attrs):
# 先创建类对象
new_class = super().__new__(cls, name, bases, attrs)
return new_class # 返回创建好的类对象
def __init__(cls, name, bases, attrs):
# 初始化类对象:添加random_id属性
cls.random_id = random.randint(0, 100)
super().__init__(name, bases, attrs) # 调用父类初始化
# 测试:类A由M创建,自动拥有random_id
class A(metaclass=M):
pass
print(A.random_id) # 输出:随机整数(如42,每次运行不同)

__new__
与__init__
的区别
对比维度 | __new__ |
__init__ |
---|---|---|
调用时机 | 类创建前(先执行) | 类创建后(后执行) |
作用对象 | 待创建的类对象 | 已创建的类对象 |
核心任务 | 创建类对象 | 初始化类对象 |
返回值 | 必须返回类对象 | 无需返回(或返回None) |
3.3. __call__
- 调用时机 :当调用目标类创建实例时(如
o = A()
),元类的__call__
方法被调用; - 核心作用:控制实例的创建流程(如实现单例模式:确保类只有一个实例);
- 参数含义 :
cls
:目标类(如A,即元类M的实例);*args
:创建实例时传入的位置参数(如A(1, 2)
中的1, 2
);**kwargs
:创建实例时传入的关键字参数;
- 返回值 :通常返回创建好的实例(如
super().__call__(*args, **kwargs)
)。
例如:确保类A只有一个实例,多次调用A()
返回同一个对象。
python
class M(type):
# 用元类的属性存储实例(确保唯一)
_instance = None
def __call__(cls, *args, **kwargs):
# 判断实例是否已存在
if cls._instance is None:
# 调用父类的__call__,创建实例(底层会调用A的__new__和__init__)
cls._instance = super().__call__(*args, **kwargs)
# 返回已存在的实例(确保唯一)
return cls._instance
# 测试:类A由M创建,实现单例
class A(metaclass=M):
pass
# 多次创建实例,实际是同一个对象
o1 = A()
o2 = A()
print(o1 is o2) # 输出:True(o1和o2是同一个实例)
当执行o = A()
时,实际调用流程是:
M.__call__(A, *args, **kwargs)
→ 内部调用A.__new__
创建实例 → 调用A.__init__
初始化实例 → 返回实例。
4. 应用场景
元类并非日常开发必需品,仅用于解决"多个类需要统一遵循某一规则"的场景------这类场景用继承难以实现(继承只能管控子类,元类可管控所有由它创建的类)。
常见应用场景总结:
- 统一管控类的属性/方法 :如禁止特定命名的方法(
test_
开头)、强制添加必需属性(如version
); - 实现设计模式:如单例模式(确保类只有一个实例)、工厂模式(统一创建实例的逻辑);
- 自动生成代码:如根据配置动态给类添加方法(无需手动定义);
- 框架级别的统一配置 :如Django的ORM中,用元类(
ModelBase
)统一管理模型类的创建,自动关联数据库表。
5. super
调用
在元类的方法中使用super()
时,__new__
与__init__
/__call__
的写法不同,容易踩坑。
① __new__
中使用super()
:必须传cls
__new__
是元类的静态方法(隐式),调用super()
时需明确传入元类本身(cls
)和当前类名(name
可选,通常传cls
):
python
class M(type):
def __new__(cls, name, bases, attrs):
# 正确写法:super().__new__(cls, name, bases, attrs)
return super().__new__(cls, name, bases, attrs)
# 错误写法:super().__new__(name, bases, attrs)(缺少cls参数)
② __init__
/__call__
中使用super()
:无需传cls
__init__
和__call__
是元类的实例方法,调用super()
时无需额外传参(self
会自动关联):
python
class M(type):
def __init__(cls, name, bases, attrs):
# 正确写法:super().__init__(name, bases, attrs)
super().__init__(name, bases, attrs)
# 错误写法:super().__init__(cls, name, bases, attrs)(多传了cls参数)
def __call__(cls, *args, **kwargs):
# 正确写法:super().__call__(*args, **kwargs)
return super().__call__(*args, **kwargs)
__new__
负责创建类对象,需要明确知道"由哪个元类创建"(因此需传cls
);__init__
/__call__
负责初始化类对象/创建实例,此时元类已确定(self
即元类实例),无需额外传参。
6. 总结
- 元类是"创建类的类" :普通类是元类的实例,默认元类是
type
; - 元类的关键方法 :
__new__
:类创建前执行,创建类对象;__init__
:类创建后执行,初始化类对象;__call__
:实例化类时执行,创建实例;
- 元类的作用:解决"多个类统一管控"的问题,继承无法替代;
- 使用方式 :定义元类(继承
type
)→ 目标类用metaclass
参数指定元类。
元类是Python面向对象的高级特性,掌握它能让你更深入理解Python的类模型,但无需过度追求------先保证基础功能的简洁性和可读性,再考虑用元类解决复杂场景。