2011-08-22 62 views
1

我想创造我在这里创造了一流的元类:ctypes variable length structures与ctypes的结构冲突元类

我要简化点类,所以它看起来像这样(的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 

这是元类我到目前为止:

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 

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

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

回答

3

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

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

import ctypes 

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

该方法的缺点是限制了元类的使用。如果您只打算将它用于ctypes.Structure的子类,则这可能是确定的。

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

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

class Points(c.Structure, metaclass=PointsMetaClass): 
    # ... 

始终确保您使用super()而不是硬编码type在元类__new__

return super(VariableMeta, cls).__new__(cls, name, bases, dct) 

正如圭多曾写道:在Python中编写元类will cause your head to explode

+0

非常明确的答案!谢谢! – Jake