使用元类

Python 元类(Metaclass)深入解析

动态类型与 type() 函数

Python 作为动态语言,其类和函数的定义是在运行时动态创建的。这与静态语言(如 Java、C++)有显著区别。

type() 的基本用法

type() 函数有两种主要用途:

  1. 查看对象的类型
  2. 动态创建类
# 查看类型
>>> type(123)
<class 'int'>
>>> type('hello')
<class 'str'>

动态创建类

我们可以使用 type() 动态创建类,而无需使用 class 关键字:

# 定义一个方法
def say_hello(self, name='world'):
    print(f'Hello, {name}.')

# 使用 type() 创建类
Hello = type('Hello', (object,), {'hello': say_hello})

# 使用类
h = Hello()
h.hello()  # 输出: Hello, world.

type() 创建类时需要三个参数:

  1. 类名(字符串)
  2. 继承的父类元组(支持多重继承)
  3. 包含类属性和方法的字典

元类(Metaclass)深入

什么是元类

元类是类的类,它控制类的创建行为。简单来说:

  • 普通类创建实例
  • 元类创建类

关系链:元类 → 类 → 实例

自定义元类

元类通常继承自 type,并以 Metaclass 结尾命名:

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # 添加一个 add 方法
        attrs['add'] = lambda self, value: self.append(value)
        return super().__new__(cls, name, bases, attrs)

__new__ 方法参数:

  • cls:当前准备创建的类
  • name:类名
  • bases:父类元组
  • attrs:类属性和方法字典

使用元类

class MyList(list, metaclass=ListMetaclass):
    pass

L = MyList()
L.add(1)  # 正常调用

实际应用:实现简单 ORM 框架

ORM(Object-Relational Mapping)是将数据库表映射为 Python 类的技术。

基础字段类

class Field:
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return f'<{self.__class__.__name__}:{self.name}>'

class StringField(Field):
    def __init__(self, name):
        super().__init__(name, 'varchar(100)')

class IntegerField(Field):
    def __init__(self, name):
        super().__init__(name, 'bigint')

元类实现

class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        if name == 'Model':
            return super().__new__(cls, name, bases, attrs)
        
        print(f'Found model: {name}')
        mappings = {}
        
        # 收集 Field 属性
        for k, v in attrs.items():
            if isinstance(v, Field):
                print(f'Found mapping: {k} ==> {v}')
                mappings[k] = v
                
        # 移除类属性中的 Field,避免实例属性覆盖
        for k in mappings:
            attrs.pop(k)
            
        attrs['__mappings__'] = mappings  # 保存字段映射
        attrs['__table__'] = name         # 假设表名与类名相同
        return super().__new__(cls, name, bases, attrs)

基类 Model

class Model(dict, metaclass=ModelMetaclass):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(f"'Model' object has no attribute '{key}'")
            
    def __setattr__(self, key, value):
        self[key] = value
        
    def save(self):
        fields = []
        params = []
        args = []
        
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
            
        sql = f"INSERT INTO {self.__table__} ({','.join(fields)}) VALUES ({','.join(params)})"
        print(f'SQL: {sql}')
        print(f'ARGS: {args}')

使用示例

class User(Model):
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()

输出:

Found model: User
Found mapping: id ==> <IntegerField:id>
Found mapping: name ==> <StringField:username>
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
SQL: INSERT INTO User (id,username,email,password) VALUES (?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']

总结

  1. type() 是 Python 中所有类的默认元类
  2. 元类允许我们拦截类的创建过程,实现强大的定制功能
  3. ORM 是元类的典型应用场景
  4. 元类虽然强大,但应谨慎使用,多数情况下可以通过其他更简单的方式实现需求

元类是 Python 中非常高级的特性,理解它有助于深入掌握 Python 的面向对象机制。