← 返回 Day 46 正文

Day 46 · 图解

Day 046 — 元类(Metaclass)图解

1. Python 对象层级关系

┌─────────────────────────────────────────────────┐
│                  Python 对象模型                 │
├─────────────────────────────────────────────────┤
│                                                 │
│   普通对象(实例)                               │
│   ┌─────────────┐                               │
│   │   dog_instance  │──type──▶  Dog (类)        │
│   └─────────────┘                               │
│                                                 │
│   类对象                                         │
│   ┌─────────────┐                               │
│   │     Dog      │──type──▶  type (元类)        │
│   └─────────────┘                               │
│                                                 │
│   元类对象                                       │
│   ┌─────────────┐                               │
│   │     type     │──type──▶  type (自身)        │
│   └─────────────┘                               │
│                                                 │
└─────────────────────────────────────────────────┘

2. type() 的两种用法

type() 的两种用法
═══════════════════════════════════════════

用法一:查询类型
─────────────────
    type(42)  →  <class 'int'>
    type("hi") →  <class 'str'>

用法二:动态创建类
─────────────────
    MyClass = type('MyClass', (object,), {'x': 1})
    
    等价于:
    class MyClass:
        x = 1

3. 元类调用流程

用户定义类                     Python 解释器
═══════════════════════════════════════════════════

class Dog(Animal):
    legs = 4
    def bark(self): ...

           │
           ▼
    ┌──────────────────────────────┐
    │  1. 检查是否有 metaclass     │
    │     默认: type               │
    └──────────┬───────────────────┘
               │
               ▼
    ┌──────────────────────────────┐
    │  2. 调用 metaclass.__new__   │
    │     创建类对象               │
    │     (可修改 attrs)           │
    └──────────┬───────────────────┘
               │
               ▼
    ┌──────────────────────────────┐
    │  3. 调用 metaclass.__init__  │
    │     初始化类                 │
    └──────────┬───────────────────┘
               │
               ▼
    ┌──────────────────────────────┐
    │  4. Dog 类对象诞生 🎉        │
    └──────────────────────────────┘

4. 自定义元类 vs 装饰器 vs init_subclass

选择指南
═══════════════════════════════════════════════════

┌────────────────┬────────────┬────────────┬─────────────────┐
│   特性          │   元类     │  装饰器     │ __init_subclass__│
├────────────────┼────────────┼────────────┼─────────────────┤
│ 作用范围        │ 所有子类   │ 单个类      │ 子类            │
│ 复杂度         │ 高         │ 低          │ 中              │
│ 可读性         │ 差         │ 好          │ 好              │
│ 能否修改类名    │ 能         │ 不能        │ 不能            │
│ 能否阻止类创建  │ 能         │ 不能        │ 不能            │
└────────────────┴────────────┴────────────┴─────────────────┘

经验法则:
  能用装饰器 → 用装饰器
  能用 __init_subclass__ → 用 __init_subclass__
  都不行 → 才考虑元类

5. ORM 字段验证流程

定义模型                     运行时验证
═══════════════════════════════════════════════════

class User(Model):                user = User(name="Alice", email="a@b.com")
    name = StringField()                    │
    email = EmailField()                    ▼
    age = AgeField()              ┌────────────────────┐
         │                        │  Model.__init__    │
         ▼                        │  遍历 _fields      │
┌────────────────────┐            │  设置字段值        │
│  ModelMeta.__new__ │            │  检查必填字段      │
│                    │            └─────────┬──────────┘
│  1. 收集 Field 实例│                      │
│  2. 设置 field.name│                      ▼
│  3. 存入 _fields   │            ┌────────────────────┐
└────────────────────┘            │  user.validate()   │
                                  │  遍历 _fields      │
                                  │  调用 field.validate│
                                  │  收集错误          │
                                  └─────────┬──────────┘
                                            │
                                            ▼
                                  通过 ✅ 或 抛出 ValidationError ❌

6. Meta 三方法对比

__new__ vs __init__ vs __call__
═══════════════════════════════════════════════════

class Meta(type):
    def __new__(mcs, name, bases, attrs):
        """创建类对象 — 返回 cls"""
        return super().__new__(mcs, name, bases, attrs)
    
    def __init__(cls, name, bases, attrs):
        """初始化已创建的类 — 无返回值"""
        super().__init__(name, bases, attrs)
    
    def __call__(cls, *args, **kwargs):
        """创建类的实例 — 返回 instance"""
        return super().__call__(*args, **kwargs)

调用时机:
  Meta.__new__   ← class Foo: 时调用(创建类)
  Meta.__init__  ← class Foo: 时调用(初始化类)
  Meta.__call__  ← Foo() 时调用(创建实例)