是否可以创建间接递归 ctypes.Structure 类型?

Is it at all possible to create indirectly recursive ctypes.Structure types?

这与 #1228158 or #28879604 不同。它很相似,但有一点不同。

创建引用其自身类型的递归类型很简单:

A = type('A', (ctypes.Structure,), {})
A._fields_ = [('another_a', ctypes.POINTER(A))]

或者,如果您愿意:

class A(ctypes.Structure):
    pass
A._fields_ = [('another_a', ctypes.POINTER(A))]

同样的事情。如果他们不是一回事,请教育我!

但我正在尝试将 C structs 和 typedefs 机器翻译成 ctypes.Structures。我希望 Python 端的名称和关系反映 C 端的名称和关系。如果一个函数返回一个 uint32typedef 编辑为 consumer_id,我希望 Python 一侧的对象具有更具描述性的名称。现在,这是一种经常发生的事情:

typedef dummy_type official_type;
typedef struct dummy_struct {
    official_type *another_struct;
} dummy_type;

无论我如何曲折,我都无法实现Python中的这种关系。中间名称 可能 没有在任何地方使用,所以目前我们的想法是检测这种情况,只是让 official_type 成为 ctypes.Structure 引用本身。并且可能使 dummy_typestruct dummy_struct 类型引用它们自己。在二进制级别,在 C 端,它们都是等价的。

但我真正想做的是:

Struct_dummy_struct = type('struct_dummy_struct', (ctypes.Structure,), {})
Dummy_type = type('dummy_type', (Struct_dummy_struct,), {})
Official_type = type('official_type', (Dummy_type,), {})
Struct_dummy_struct._fields_ = [('another_struct', ctypes.POINTER(Official_type))]

当然,这是不可能的:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: _fields_ is final

考虑到 ctypes 的工作方式,我认为我尝试做的事情在理论上是不可能的,但如果有人能告诉我有办法,我会很高兴!

您不需要在 python 中使用相同的构造:

class official_type(ctypes.Structure):
    pass
official_type._fields_ = [("another_struct", ctypes.POINTER(official_type))]
first_instance = official_type()
second_instance = official_type()
first_instance.another_struct = ctypes.pointer(second_instance)
print first_instance.another_struct

<__main__.LP_official_type object at ...>

Ctypes 有一个时髦的结构完成过程,如果你深入研究单元测试,你会发现类似的东西:

Structure/Union classes must get 'finalized' sooner or later, when one of these things happen:

  1. _fields_ is set.
  2. An instance is created.
  3. The type is used as field of another Structure/Union.
  4. The type is subclassed

When they are finalized, assigning fields is no longer allowed.

也许您使用类型的 class 定义弄乱了过程。