You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用attr模块创建元类触发TypeError,求Python2/3兼容方案

问题分析与解决方案

首先,咱们来拆解你遇到的 TypeError 问题:当用 @attrs 装饰元类时,attrs 会自动生成一个仅处理你定义的 my_attribute 的 __init__ 方法,但元类的 __init__ 在 Python 创建类时,必须接收四个参数:cls(被创建的类)、name(类名)、bases(父类元组)、namespace(类的命名空间)。这两个 __init__ 的参数签名完全冲突,所以触发了参数数量不匹配的错误。

接下来提供两种适配方案,同时兼顾 Python 2/3 兼容性:


方案一:手动兼容元类的 __init__ 逻辑

核心思路是禁用 attrs 自动生成的 __init__,手动编写元类的初始化方法,先处理元类必备的参数,再初始化 attrs 定义的属性。

import attr
from abc import ABCMeta
from six import add_metaclass

# 禁用attrs自动生成__init__,手动实现兼容逻辑
@attr.define(init=False)
class MetaClass(ABCMeta):
    my_attribute = attr.ib()

    def __new__(cls, name, bases, namespace):
        # 提取Python2中类定义里的元类参数(兼容用)
        kwargs = namespace.pop('__metaclass_kwargs__', {})
        # 创建类实例
        new_cls = super().__new__(cls, name, bases, namespace)
        # 手动调用__init__并传递参数
        cls.__init__(new_cls, name, bases, namespace, **kwargs)
        return new_cls

    def __init__(self, name, bases, namespace, **kwargs):
        # 先完成元类本身的初始化逻辑
        super().__init__(name, bases, namespace)
        # 初始化attrs定义的属性
        for field in attr.fields(MetaClass):
            if field.name in kwargs:
                setattr(self, field.name, kwargs[field.name])
        # 验证属性合法性(可选)
        attr.validate(self)

# Python 3 用法
class MyClass(object, metaclass=MetaClass, my_attribute="Python3测试值"):
    pass

# Python 2 用法
@add_metaclass(MetaClass)
class MyClass2(object):
    __metaclass_kwargs__ = {"my_attribute": "Python2测试值"}

方案二:放弃元类装饰,转而让元类自动装饰子类

如果你只是想批量创建带属性的简单存储类,其实不需要用 attrs 装饰元类,而是让元类自动给子类加上 @attrs 装饰器,这样更简洁:

from attr import attrs, attrib
from abc import ABCMeta
from six import add_metaclass

class MetaClass(ABCMeta):
    def __new__(cls, name, bases, namespace):
        # 自动给创建的子类添加@attrs装饰
        new_cls = super().__new__(cls, name, bases, namespace)
        return attrs(new_cls)

# Python 3 用法
class MyClass(object, metaclass=MetaClass):
    attr1 = attrib()
    attr2 = attrib()

# Python 2 用法
@add_metaclass(MetaClass)
class MyClass2(object):
    attr1 = attrib()
    attr2 = attrib()

这种方式既实现了批量创建存储类的需求,又避开了元类与 attrs 的初始化冲突,推荐优先考虑。

内容的提问来源于stack exchange,提问作者Torilla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:14:31