用内省打印ctypes“Structure”的所有字段

时间:2014-01-08 03:11:59

标签: python reflection ctypes

test.c的:

#include <stdio.h>
#include <stdlib.h>

struct s {
    char a;
    int b;
    float c;
    double d;
};

struct s *create_struct()
{
    struct s *res = malloc(sizeof(struct s));
    res->a = 1; res->b = 2; res->c = 3.0f; res->d = 4.0;
    return res;
}

test.py:

from ctypes import *

class S(Structure):
    _fields_ = [
        ('a', c_byte),
        ('b', c_int),
        ('c', c_float),
        ('d', c_double)
    ]

lib = CDLL('./test.so')

create_struct = lib.create_struct
create_struct.restype = POINTER(S)
create_struct.argtypes = []

s_ptr = create_struct()
s = s_ptr.contents

print s._fields_[0][0], s.a
print s._fields_[1][0], s.b
print s._fields_[2][0], s.c
print s._fields_[3][0], s.d
print s.__dict__

输出:

a 1
b 2
c 3.0
d 4.0
{}

我想调整上面的python脚本来打印我的结构的每个字段,而不必为每个字段明确地做。据我所知,这可以使用__dict__属性完成,但我的是空的。对于扩展ctypes.Structure的类有什么办法吗?

3 个答案:

答案 0 :(得分:14)

如何使用getattr

>>> from ctypes import *
>>>
>>> class S(Structure):
...     _fields_ = [
...         ('a', c_byte),
...         ('b', c_int),
...         ('c', c_float),
...         ('d', c_double)
...     ]
...
>>> s = S(1, 2, 3, 4.0)
>>>
>>> for field_name, field_type in s._fields_:
...     print field_name, getattr(s, field_name)
...
a 1
b 2
c 3.0
d 4.0

<强>更新

如果结构(或联合)中存在位域,则迭代_fields_会产生3个项目的元组,这将导致ValueError。为了防止您需要调整代码:

...

for field in s._fields_:
    print field[0], getattr(s, field[0])

答案 1 :(得分:1)

这是@fattru的答案,作为ctypes类的__str__方法:

def __str__(self):
    return "{}: {{{}}}".format(self.__class__.__name__,
                               ", ".join(["{}: {}".format(field[0],
                                                          getattr(self,
                                                                  field[0]))
                                          for field in self._fields_]))

答案 2 :(得分:0)

我刚刚想到了这个,对于我正在处理的项目,它具有几个我想能够漂亮打印的C结构(在我的Jupyter笔记本中):

>>> # https://stackoverflow.com/a/62011887/76452
>>>
>>> from ctypes import Structure, c_byte, c_int, c_float, c_double
>>>
>>>
>>> class MyStructure(Structure):
...    
...    def __repr__(self) -> str:
...        values = ", ".join(f"{name}={value}"
...                          for name, value in self._asdict().items())
...        return f"<{self.__class__.__name__}: {values}>"
>>>
>>>    def _asdict(self) -> dict:
...        return {field[0]: getattr(self, field[0])
...                for field in self._fields_}
>>> 
>>>
>>> class S(MyStructure):
...     _fields_ = (
...         ('a', c_byte),
...         ('b', c_int),
...         ('c', c_float),
...         ('d', c_double)
...     )
>>>
>>> s = S(1, 2, 3.0, 4.0)
>>> s
<S: a=1, b=2, c=3.0, d=4.0>