有一种方法可以用字典初始化结构:
fooData= {'y': 1, 'x': 2}
fooStruct = ffi.new("foo_t*", fooData)
fooBuffer = ffi.buffer(fooStruct)
是否有一些准备好的功能来进行转换?
fooStruct = ffi.new("foo_t*")
(ffi.buffer(fooStruct))[:] = fooBuffer
fooData= convert_to_python( fooStruct[0] )
我必须自己使用ffi.typeof(“foo_t”)。字段吗?
到目前为止我想出了这个代码:
def __convert_struct_field( s, fields ):
for field,fieldtype in fields:
if fieldtype.type.kind == 'primitive':
yield (field,getattr( s, field ))
else:
yield (field, convert_to_python( getattr( s, field ) ))
def convert_to_python(s):
type=ffi.typeof(s)
if type.kind == 'struct':
return dict(__convert_struct_field( s, type.fields ) )
elif type.kind == 'array':
if type.item.kind == 'primitive':
return [ s[i] for i in range(type.length) ]
else:
return [ convert_to_python(s[i]) for i in range(type.length) ]
elif type.kind == 'primitive':
return int(s)
有更快的方法吗?
答案 0 :(得分:2)
Arpegius的解决方案对我来说很好用,而且非常优雅。我根据Selso的建议使用检查来实现了一个解决方案。 dir()可以代替inspect。
from inspect import getmembers
from cffi import FFI
ffi = FFI()
from pprint import pprint
def cdata_dict(cd):
if isinstance(cd, ffi.CData):
try:
return ffi.string(cd)
except TypeError:
try:
return [cdata_dict(x) for x in cd]
except TypeError:
return {k: cdata_dict(v) for k, v in getmembers(cd)}
else:
return cd
foo = ffi.new("""
struct Foo {
char name[6];
struct {
int a, b[3];
} item;
} *""",{
'name': b"Foo",
'item': {'a': 3, 'b': [1, 2, 3]}
})
pprint(cdata_dict(foo))
输出:
{'item': {'a': 3, 'b': [1, 2, 3]}, 'name': b'Foo'}
答案 1 :(得分:0)
你的代码很好。
即使在CFFI中有内置方式,也不会是你需要的。实际上,您可以说ffi.new("foo_t*", {'p': p1})
其中p1
是另一个cdata,但您无法递归传递包含更多字典的字典。在相反的方向也是如此:你会得到一个字典,将字段名称映射到“值”,但值本身无论如何都会是更多的cdata对象,而不是递归更多的字典。
答案 2 :(得分:0)
这段代码对我来说不起作用,因为有些struct成员是“指针”类型,它会导致在dict中存储“none”。
我是一个Python菜鸟,但是检查模块可能是另一个起点,也是打印“简单”数据的一种较短方式。然后我们将迭代结果以展开数据结构。
例如,使用以下示例:
struct foo {
int a;
char b[10];
};
使用inspect.getmembers(obj)我得到以下结果:
[('a', 10), ('b', <cdata 'char[10]' 0x7f0be10e2824>)]