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

继承type与typing.Mapping时触发__subclasses__ TypeError问题求助

解决同时继承type与Mapping的元类引发的TypeError问题

解决方案

要解决这个问题,需重写__subclasscheck__方法以规避ABC(抽象基类)与type的方法冲突,同时实现Mapping要求的抽象方法来满足接口规范:

import dataclasses
from collections.abc import Mapping

class MyDataclassMeta(type, Mapping):
    # 实现Mapping的抽象方法(可根据业务需求自定义逻辑)
    def __getitem__(self, key):
        return getattr(self, key)
    
    def __len__(self):
        return len([attr for attr in dir(self) if not attr.startswith('__')])
    
    def __iter__(self):
        return iter([attr for attr in dir(self) if not attr.startswith('__')])
    
    # 重写__subclasscheck__,分离type与Mapping的子类检查逻辑
    def __subclasscheck__(cls, subclass):
        # 先检查是否符合type的子类关系
        if type.__subclasscheck__(cls, subclass):
            return True
        # 再检查是否符合Mapping的子类要求
        return Mapping.__subclasscheck__(cls, subclass)

验证代码

修改后的元类可正常用于dataclass:

@dataclasses.dataclass
class MyDataclass(metaclass=MyDataclassMeta):
    name: str
    age: int

也能正常处理Mapping虚拟子类的注册:

@Mapping.register
class CompletelyUnrelatedClass:
    def __getitem__(self, key):
        pass
    def __len__(self):
        pass
    def __iter__(self):
        pass

问题根源

当类同时继承type和Mapping(Mapping继承自ABC)时,ABC的默认__subclasscheck__逻辑会递归触发子类检查,但type的__subclasses__方法需要绑定到实例调用,在ABC的检查流程中被当作未绑定方法调用,因此抛出TypeError: descriptor '__subclasses__' of 'type' object needs an argument。

重写__subclasscheck__后,我们显式拆分type和Mapping的子类检查逻辑,避免了递归调用和方法绑定错误。

原始问题与复现

需求

定义一个同时具备以下两个功能的类:

  • 作为dataclass的元类(继承type)
  • 具备映射(Mapping)行为(继承typing.Mapping)

最小复现代码

import dataclasses, typing

class MyDataclassMeta(type, typing.Mapping):
    # 可在此实现Mapping的抽象方法(与报错无关)
    pass

# 取消注释触发报错1
# @dataclasses.dataclass
# class MyDataclass(metaclass=MyDataclassMeta):
#     pass

# 取消注释触发报错2
# @typing.Mapping.register
# class CompletelyUnrelatedClass:
#     pass

if __name__ == "__main__":
    pass

报错信息

报错1(用作dataclass元类时)

Traceback (most recent call last):
  File "foo.py", line 10, in <module>
    class MyDataclass(metaclass=MyDataclassMeta):
  File "D:\Python38\lib\dataclasses.py", line 1019, in dataclass
    return wrap(cls)
  File "D:\Python38\lib\dataclasses.py", line 1011, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
  File "D:\Python38\lib\dataclasses.py", line 991, in _process_class
    str(inspect.signature(cls)).replace(' -> None', ''))
  File "D:\Python38\lib\inspect.py", line 3105, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
  File "D:\Python38\lib\inspect.py", line 2854, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
  File "D:\Python38\lib\inspect.py", line 2307, in _signature_from_callable
    if _signature_is_builtin(obj):
  File "D:\Python38\lib\inspect.py", line 1847, in _signature_is_builtin
    obj in (type, object))
  File "D:\Python38\lib\_collections_abc.py", line 685, in __eq__
    if not isinstance(other, Mapping):
  File "D:\Python38\lib\abc.py", line 98, in __instancecheck__
    return _abc_instancecheck(cls, instance)
  File "D:\Python38\lib\abc.py", line 102, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
  File "D:\Python38\lib\abc.py", line 102, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
TypeError: descriptor '__subclasses__' of 'type' object needs an argument

报错2(注册Mapping虚拟子类时)

Traceback (most recent call last):
  File "foo.py", line 15, in <module>
    class CompletelyUnrelatedClass:
  File "D:\Python38\lib\abc.py", line 94, in register
    return _abc_register(cls, subclass)
  File "D:\Python38\lib\abc.py", line 102, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
  File "D:\Python38\lib\abc.py", line 102, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
TypeError: descriptor '__subclasses__' of 'type' object needs an argument

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:42:31