全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-19 10 分钟 ✍️ juanwangdev

Python自定义元类

自定义元类通过继承type并重写__new____init__,可在类创建时注入自定义逻辑。

元类基础结构

Python
class CustomMeta(type):
    "自定义元类模板"

    def __new__(mcs, name, bases, namespace):
        "创建类对象"
        print(f"CustomMeta.__new__: {name}")

        # 可在此修改 namespace、bases 等
        cls = super().__new__(mcs, name, bases, namespace)
        return cls

    def __init__(cls, name, bases, namespace):
        "初始化类对象"
        print(f"CustomMeta.__init__: {name}")
        super().__init__(name, bases, namespace)

    def __call__(cls, *args, **kwargs):
        "控制实例创建"
        print(f"CustomMeta.__call__: {cls.__name__}")
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=CustomMeta):
    pass

obj = MyClass()
# 输出顺序:
# CustomMeta.__new__: MyClass
# CustomMeta.__init__: MyClass
# CustomMeta.__call__: MyClass(实例创建时)

元类参数顺序

Python
# __new__ 和 __init__ 的参数说明
class DetailedMeta(type):
    def __new__(mcs, name, bases, namespace, **kwargs):
        "
        mcs: 元类本身CustomMeta
        name: 类名字符串
        bases: 基类元组
        namespace: 类属性字典
        kwargs: 类定义时传入的额外参数class Foo(metaclass=Meta, arg=1)
        "
        print(f"元类: {mcs.__name__}")
        print(f"类名: {name}")
        print(f"基类: {[b.__name__ for b in bases]}")
        print(f"属性: {list(namespace.keys())[:5]}")
        print(f"额外参数: {kwargs}")

        # kwargs 通常传递给 __init__
        cls = super().__new__(mcs, name, bases, namespace)
        cls._meta_args = kwargs  # 存储额外参数
        return cls

    def __init__(cls, name, bases, namespace, **kwargs):
        super().__init__(name, bases, namespace)

class Example(metaclass=DetailedMeta, version="1.0", debug=True):
    attr = 123

属性自动处理

Python
class UppercaseMeta(type):
    "自动将属性名转为大写"

    def __new__(mcs, name, bases, namespace):
        new_namespace = {}

        for key, value in namespace.items():
            if key.startswith('__') and key.endswith('__'):
                new_namespace[key] = value  # 保留特殊属性
            elif callable(value):
                new_namespace[key] = value  # 保留方法
            else:
                new_namespace[key.upper()] = value  # 属性大写

        return super().__new__(mcs, name, bases, new_namespace)

class Config(metaclass=UppercaseMeta):
    host = "localhost"
    port = 8080
    debug = True

print(Config.HOST)    # localhost
print(Config.PORT)    # 8080
print(Config.DEBUG)   # True
# Config.host  # AttributeError
Python
class TypedMeta(type):
    "属性类型检查"

    def __new__(mcs, name, bases, namespace):
        # 检查 _types 定义的类型约束
        if '_types' in namespace:
            types_spec = namespace['_types']
            for attr_name, expected_type in types_spec.items():
                if attr_name in namespace:
                    actual_value = namespace[attr_name]
                    if not isinstance(actual_value, expected_type):
                        raise TypeError(
                            f"{name}.{attr_name} 应为 {expected_type.__name__}, "
                            f"实际为 {type(actual_value).__name__}"
                        )

        return super().__new__(mcs, name, bases, namespace)

class TypedClass(metaclass=TypedMeta):
    _types = {
        'name': str,
        'count': int,
    }
    name = "valid"
    count = 10

# name = 123 会触发 TypeError

自动注册模式

Python
class RegistryMeta(type):
    "自动注册所有子类"

    _registry = {}

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)

        # 注册类(排除基类)
        if bases:  # 非顶层基类
            mcs._registry[name] = cls

        return cls

    @classmethod
    def get_registry(mcs):
        return dict(mcs._registry)

class PluginBase(metaclass=RegistryMeta):
    "插件基类"

class PluginA(PluginBase):
    name = "plugin_a"

class PluginB(PluginBase):
    name = "plugin_b"

print(RegistryMeta.get_registry())
# {'PluginA': <class PluginA>, 'PluginB': <class PluginB>}
Python
# 按类型注册
class HandlerRegistry(type):
    handlers = {}

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)

        if 'handler_type' in namespace:
            handler_type = namespace['handler_type']
            mcs.handlers[handler_type] = cls

        return cls

class Handler(type):
    pass

class TextHandler(metaclass=HandlerRegistry):
    handler_type = 'text'
    def process(self, data):
        return data.strip()

class ImageHandler(metaclass=HandlerRegistry):
    handler_type = 'image'
    def process(self, data):
        return f"processed: {data}"

print(HandlerRegistry.handlers)
# {'text': TextHandler, 'image': ImageHandler}

强制接口实现

Python
class InterfaceMeta(type):
    "强制子类实现指定方法"

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)

        # 检查是否定义了 _required_methods
        if hasattr(cls, '_required_methods'):
            required = cls._required_methods

            # 基类不需要检查
            if name != 'Interface':
                missing = []
                for method in required:
                    if method not in namespace:
                        # 检查是否从基类继承
                        if not any(hasattr(b, method) for b in bases):
                            missing.append(method)

                if missing:
                    raise NotImplementedError(
                        f"{name} 必须实现方法: {missing}"
                    )

        return cls

class Interface(metaclass=InterfaceMeta):
    _required_methods = ['process', 'validate']

class ValidImpl(Interface):
    def process(self):
        pass

    def validate(self):
        pass

# class InvalidImpl(Interface):
#     def process(self):
#         pass
# NotImplementedError: 必须实现 validate

控制实例创建

Python
class SingletonMeta(type):
    "单例元类"

    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class Singleton(metaclass=SingletonMeta):
    def __init__(self, value):
        self.value = value

s1 = Singleton(1)
s2 = Singleton(2)

print(s1.value)     # 1(第一次创建)
print(s2.value)     # 1(同一实例)
print(s1 is s2)     # True
Python
class NoInstanceMeta(type):
    "禁止实例化的元类"

    def __call__(cls, *args, **kwargs):
        raise TypeError(f"{cls.__name__} 不允许实例化")

class AbstractClass(metaclass=NoInstanceMeta):
    "抽象类,仅作为接口"

# AbstractClass()  # TypeError

prepare 自定义命名空间

Python
class OrderedDictMeta(type):
    "使用有序字典作为命名空间"

    @classmethod
    def __prepare__(mcs, name, bases):
        return {}  # Python 3.6+ 默认字典保持顺序

    def __new__(mcs, name, bases, namespace):
        # 查看属性定义顺序
        order = [k for k in namespace if not k.startswith('__')]
        cls = super().__new__(mcs, name, bases, namespace)
        cls._attribute_order = order
        return cls

class OrderedClass(metaclass=OrderedDictMeta):
    first = 1
    second = 2
    third = 3

print(OrderedClass._attribute_order)  # ['first', 'second', 'third']

多元类冲突

Python
class MetaA(type):
    pass

class MetaB(type):
    pass

class ClassA(metaclass=MetaA):
    pass

class ClassB(metaclass=MetaB):
    pass

# 多继承时的元类冲突
# class Conflict(ClassA, ClassB):  # TypeError: 元类冲突

# 解决方案1:统一元类
class UnifiedMeta(MetaA, MetaB):
    pass

class Unified(ClassA, ClassB, metaclass=UnifiedMeta):
    pass

# 解决方案2:显式指定元类
class Explicit(ClassA, ClassB, metaclass=MetaA):
    pass  # 继承MetaA(需兼容MetaB)

要点总结

  1. **__new__**创建类对象,可修改属性、基类
  2. **__init__**初始化类对象,可添加额外逻辑
  3. **__call__**控制实例创建,可实现单例模式
  4. **__prepare__**自定义命名空间容器
  5. 多继承时需解决元类冲突,确保统一元类

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python属性动态管理
下一篇 → Python多进程并发模式
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库