Python多重继承元类错误

Python多重继承元类错误,python,multiple-inheritance,metaclass,Python,Multiple Inheritance,Metaclass,我正在尝试从ABC和ctypes.Structure继承,但是我得到了多个继承和元类错误 我做错了什么 我的代码如下: from ctypes import * from abc import ABC, abstractmethod, ABCMeta class FinalMeta(ABCMeta, type(Structure)): def __new__(mcs, name, bases, namespace, **kwargs): print("Fina

我正在尝试从ABC和
ctypes.Structure继承
,但是我得到了多个继承和元类错误

我做错了什么

我的代码如下:

from ctypes import *
from abc import ABC, abstractmethod, ABCMeta

class FinalMeta(ABCMeta, type(Structure)):
    def __new__(mcs, name, bases, namespace, **kwargs):
        print("FinalMeta.__new__(mcs, name, bases, namespace, **kwargs)")
        print("  mcs =", mcs)
        print("  name =", name)
        print("  bases =", bases)
        print("  namespace =", namespace)
        print("  kwargs =", kwargs)
        cls = super().__new__(mcs, name, bases, namespace, **kwargs)
        print("<-- cls =", cls)
        print()
        return cls


class MessageBase(ABC, Structure, metaclass=FinalMeta):
    def __init__(self, *args, **kwargs):
        super().__init__()
    
    @property
    @abstractmethod
    def format(self):
        pass

这是行不通的。yAzou的答案看起来似乎是可行的,但事实并非如此——它跳过了关键的初始化,使MessageBase处于中断状态,最明显的症状是,即使您填写
\u字段并在具体的子类中实现抽象属性

尝试用C编写的类型执行多重继承没有得到很好的支持。行为的一部分可能是Python错误,但我怀疑它是否能正常工作。事情是这样的


\u ctypes.PyCStructType
ctypes.Structure
的元类。这个元类是用C编写的,这意味着它的
\uuuuu new\uuuuuu
是作为C级插槽的包装器生成的

tp\u new
包装器希望通过执行类似于
object.\uu new\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。为此,它:

静态PyObject*
tp_new_包装器(PyObject*self、PyObject*args、PyObject*kwds)
{
...
/*检查用户是否做了愚蠢和不安全的事情,如
对象。新的(dict)。为此,我们检查
大多数不是堆类型的派生基都是这种类型*/
staticbase=子类型;
while(staticbase&(staticbase->tp_new==slot_tp_new))
staticbase=staticbase->tp\u base;
/*如果staticbase现在为NULL,那么它是一个非常奇怪的类型。
本着向后兼容的精神(?),闭嘴吧*/
if(staticbase&&staticbase->tp\u new!=类型->tp\u new){
PyErr_格式(PyExc_类型错误,
%s.\uuuuuuuuuuuuuuu(%s)不安全,请使用%s.\uuuuuuuuuuuuuuuuuuuuuuu()“,
类型->tp\U名称,
子类型->tp_名称,
staticbase->tp_名称);
返回NULL;
}
这试图确保当您调用
ClassA.\uuuuu new\uuuuuuu(ClassB,…)时
对于用C编写的
ClassA
ClassA
ClassB
继承层次结构最底层的C类。然而,它通过
tp\u base
指针遵循一个基类链,忽略多重继承

通过初始化
tpu base
指针的方式(请参见
Objects/typeobject.c
),遵循
tpu base
指针通常会导致派生最多的c类,但这取决于每个c类向其(单个)基类的实例内存布局添加字段。
\ctypes.PyCStructType
不会这样做(它用一个奇怪的自定义dict子类替换类dict来存储其数据),因此FinalMeta的
tp_base
链变成FinalMeta->ABCMeta->type->object

由于
\ctypes.PyCStructType
不在
tp\u base
链中,
tp\u new\u wrapper
认为
type
是FinalMeta最派生的C祖先,它认为应该调用
type.\uu new\uuuu
。但是,如果调用
type.\uuuu new\uuu
,您将跳过此检查的初始化为了阻止你跳绳,让你的班级处于一种支离破碎的状态


您可能认为可以通过重新排列基址以放置
类型(结构)来解决此问题
ABCMeta
之前,但这只解决了一半的问题。您可以定义
MessageBase
类,但
ABCMeta.\uu new\uuu
不会运行,也不会进行标记
MessageBase
摘要所需的初始化

此外,还有一个完全不相关的长期问题,即即使
MessageBase
标记为抽象,您仍然可以创建它的实例。阻止实例化抽象类的检查在中,而不是
object
(以及此类类的后代)的C类不要调用
对象

File "D:\Development\messages.py", line 13, in __new__
    cls = super().__new__(mcs, name, bases, namespace, **kwargs)
  File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\abc.py", line 126, in __new__
    cls = super().__new__(mcls, name, bases, namespace, **kwargs)
TypeError: _ctypes.PyCStructType.__new__(FinalMeta) is not safe, use type.__new__()**