2011-08-22 38 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