2015-02-09 25 views
4

我在C中有一個枚舉數據類型。我應該如何在python-ctypes中聲明它?我想讓這個枚舉變量成爲一個結構的一部分,並且這個結構的賦值將通過memmove完成。分配後,我想顯示結構中每個變量的值,以及我想要顯示枚舉字符串的枚舉類型。如何在python中定義C-Enumeration類型

+1

你指的是什麼課程? – Makoto 2015-02-09 15:51:02

+0

是的。 https://docs.python.org/2/library/ctypes.html我上次checket時,addressof不是C;) – deets 2015-02-09 15:51:02

+0

「header」是Ctypes-Structure的一個實例。我想知道當我嘗試通過memmove分配「標題」 - 實例的變量時,將調用「標題」是哪個類的哪個方法。從術語memmove,我可以猜測它必須是內存拷貝,它甚至可能不知道這個拷貝在哪裏完成。因此,不會調用Ctypes-Structure類的方法。那是對的嗎? – 2015-02-09 15:59:37

回答

7

The Enumeration class suggested by Raj Kumar被打破,因爲它需要運行__init__以在變量中設置新值,因此如果在C端更改了值,則不可用。下面是其一個固定的版本:

class EnumerationType(type(c_uint)): 
    def __new__(metacls, name, bases, dict): 
     if not "_members_" in dict: 
      _members_ = {} 
      for key, value in dict.items(): 
       if not key.startswith("_"): 
        _members_[key] = value 

      dict["_members_"] = _members_ 
     else: 
      _members_ = dict["_members_"] 

     dict["_reverse_map_"] = { v: k for k, v in _members_.items() } 
     cls = type(c_uint).__new__(metacls, name, bases, dict) 
     for key,value in cls._members_.items(): 
      globals()[key] = value 
     return cls 

    def __repr__(self): 
     return "<Enumeration %s>" % self.__name__ 

class CEnumeration(c_uint): 
    __metaclass__ = EnumerationType 
    _members_  = {} 

    def __repr__(self): 
     value = self.value 
     return "<%s.%s: %d>" % (
      self.__class__.__name__, 
      self._reverse_map_.get(value, '(unknown)'), 
      value 
     ) 

    def __eq__(self, other): 
     if isinstance(other, (int, long)): 
      return self.value == other 

     return type(self) == type(other) and self.value == other.value 

現在一個可以聲明一個CEnumeration

class EBoolean(CEnumeration): 
    FALSE = 0 
    TRUE = 1 

並使用它:

class HeaderStruct(Structure): 
    _fields_ = [("param1", EBoolean), 
       ("param2", c_uint)] 

實例:

>>> header = HeaderStruct() 
>>> header.param1 
<EBoolean.FALSE: 0> 
>>> memmove(addressof(header), b'\x01', 1) # write LSB 0x01 in the boolean 
>>> header.param1 
<EBoolean.TRUE: 1> 
>>> header.param1 == EBoolean.TRUE 
True 
>>> header.param1 == 1 # as a special case compare against ints 
True 
>>> header.param1.value 
1L 
+0

嗨感謝您的答案。但是,你能解釋一下嗎?到目前爲止,分配這個變量的唯一方法是通過memmove。在我這樣做後,我可以使用getattr()讀取分配給結構中其他'c_uint'變量的值。我不確定在這個對象中調用什麼方法來獲取分配給ctypes-structure中該變量的值。 – 2015-02-09 16:52:54

+0

非常感謝。這正是我想要的。再次感謝您花時間糾正這個問題:-) – 2015-02-09 18:55:47

+1

沒問題,用元類很好的鍛鍊 – 2015-02-09 18:57:02

0

的Antti哈帕拉做了一個幻想ic工作回答!但是,當我將Python 3.2.2用於我認爲值得注意的事情時,我遇到了一些小問題。相反的:

class CEnumeration(c_uint): 
    __metaclass__ = EnumerationType 
    _members_  = {} 

你需要做的:

class CEnumeration(c_uint, metaclass = EnumerationType): 
    _members_  = {} 

而且,int和long一直在Python 3,以便統一:

def __eq__(self, other): 
     if isinstance(other, (int, long)): 
      return self.value == other 

     return type(self) == type(other) and self.value == other.value 

變爲:

def __eq__(self, other): 
     if isinstance(other, int): 
      return self.value == other 

     return type(self) == type(other) and self.value == other.value