Python CFFI 将结构转换为字典
Posted
技术标签:
【中文标题】Python CFFI 将结构转换为字典【英文标题】:Python CFFI convert structure to dictionary 【发布时间】:2013-12-25 00:33:12 【问题描述】:有一种方法可以用字典初始化结构:
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").fields 吗?
到目前为止,我想出了这段代码:
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)
有没有更快的方法?
【问题讨论】:
没有内置方式,没有。通常不需要:直接使用 cdata 对象,无需先将其转换为字典和列表。 @ArminRigo 我需要将其转换为 JSON。 【参考方案1】:Arpegius 的解决方案对我来说效果很好,而且非常优雅。我根据 Selso 的使用检查的建议实施了一个解决方案。 dir() 可以代替检查。
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'
【讨论】:
哇,我很高兴六年后有人仍然对这个问题感到不安。不幸的是,出于性能原因,我们改用 PyPy 并仅使用 cffi 结构和其他序列化方法。【参考方案2】:不幸的是,这段代码对我不起作用,因为一些结构成员是“指针”类型,它会导致在字典中存储“无”。
我是一个 Python 菜鸟,但检查模块可能是另一个起点,也是打印“简单”数据的更短方法。然后我们将遍历结果以展开数据结构。
以下面的例子为例:
struct foo
int a;
char b[10];
;
使用 inspect.getmembers(obj) 我得到以下结果:
[('a', 10), ('b', <cdata 'char[10]' 0x7f0be10e2824>)]
【讨论】:
【参考方案3】:你的代码没问题。
即使 CFFI 中有内置方式,也不是您需要的。实际上,您可以说ffi.new("foo_t*", 'p': p1)
其中p1
是另一个cdata,但是您不能递归地传递包含更多字典的字典。在相反的方向上也是如此:你会得到一个将字段名称映射到“值”的字典,但值本身无论如何都会是更多的 cdata 对象,而不是递归更多的字典。
【讨论】:
哇我不知道,甚至不测试它。希望没有带有结构字段的结构,传递给 C。无论如何,我将这个问题悬而未决,也许有人会在下一版本的 cffi 中实现该功能。以上是关于Python CFFI 将结构转换为字典的主要内容,如果未能解决你的问题,请参考以下文章