元类与 ctypes 结构冲突

Jak*_*ake 2 python metaclass

我正在尝试为我在此处创建的类创建一个元类:ctypes 可变长度结构

我想简化 Points 类,使其看起来像这样(Python 3.2):

class Points(c.Structure, metaclass=VariableMeta):
    _fields_ = [
        ('num_points', c.c_uint32),
        ('points', 'Point*self.num_points')
    ]
    def __init__(self):
        self.num_points = 0
        self.points = [0,]*MAX_SIZE
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止的元类:

class VariableMeta(type):
    def __new__(cls, name, bases, dct):
        dct['_inner_fields'] = dct['_fields_']
        dct['_fields_'] = [('_buffer', c.c_byte*MAX_PACKET_SIZE)]
        return type.__new__(cls, name, bases, dct)

    def parse(self):
        fields = []
        for name, ctype in self._inner_fields:
            if type(ctype) == str:
                ctype = eval(ctype)
            fields.append((name, ctype))
            class Inner(c.Structure, PrettyPrinter):
                _fields_ = fields
            inner = Inner.from_address(c.addressof(self._buffer))
            setattr(self, name, getattr(inner, name))
        self = inner
        return self

    def pack(self):
        fields = []
        for name, ctype in self._inner_fields:
            if type(ctype) == str:
                ctype = eval(ctype)
            fields.append((name, ctype))
        class Inner(c.Structure, PrettyPrinter):
            _fields_ = fields
        inner = Inner()
        for name, ctype in self._inner_fields:
            value = getattr(self, name)
            if type(value) == list:
                l = getattr(inner, name)
                for i in range(len(l)):
                    l[i] = getattr(self, name)[i]
            else:
                setattr(inner, name, value)
        return inner
Run Code Online (Sandbox Code Playgroud)

看起来它应该可以工作,但是当我运行它时,我收到错误:TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

我搜索了解决此问题的提示,但 ctypes 结构看起来是在 ac 库中实现的。我不知道如何解决这个问题,任何帮助或具体的解决方案表示赞赏!

Fer*_*yer 5

问题是ctypes.Structure使用它自己的自定义元类:_ctypes.StructType由于您从Structure继承了元类,因此 Python 不知道在构造类时要使用哪个元类。

您可以通过从 继承元类来解决此问题_ctypes.StructType。由于元类的名称是ctypes模块的实现细节,因此我建议编写type(ctypes.Structure)动态获取元类的方法。

import ctypes

class VariableMeta(type(ctypes.Structure)):
    pass
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是限制了元类的使用。如果您只打算将它用于 的子类,这可能没问题ctypes.Structure

另一种方法是创建一个继承两个元类的中间元类。

class PointsMetaClass(type(ctypes.Structure), VariableMeta):
    pass

class Points(c.Structure, metaclass=PointsMetaClass):
    # ...
Run Code Online (Sandbox Code Playgroud)

始终确保在元类中使用super()而不是硬编码' !type__new__

return super(VariableMeta, cls).__new__(cls, name, bases, dct)
Run Code Online (Sandbox Code Playgroud)

正如 Guido 曾经写道:用 Python 编写元类会让你的头爆炸