Python多重继承元类错误
我正在尝试从ABC和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
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__()**