2015-02-09 47 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