在 Python 中动态创建 Ctypes

Dynamically create Ctypes in Python

我有一个文件,我从中读取了一个单独项目中使用的 ctypes 的定义。我可以读取文件并获取所有必要的信息以在 Python 中创建我想要的 ctype,例如名称、字段、位域、ctype 基础 class(结构、联合、枚举等),以及包。

我希望能够根据以上信息创建一个 ctype class。我也希望这些 ctypes 是可腌制的。

我目前有两个解决方案,我觉得这两个都是 hack。

解决方案 1

手动或使用 Jinja2 等以适当的 ctype 格式生成 Python 代码对象,然后计算 python 代码对象。

此解决方案具有使用 eval 的缺点。我总是尽量远离 eval,我觉得这不是使用它的好地方。

解决方案 2

在函数中动态创建一个 ctype,如下所示:

from ctypes import Structure

def create_ctype_class(name, base, fields, pack):
    class CtypesStruct(base):
        _fields_ = fields
        _pack_ = pack
    CtypesStruct.__name__ = name
    return CtypesStruct

ctype = create_ctype_class('ctype_struct_name', ctypes.Structure,
                           [('field1', ctypes.c_uint8)], 4)

这个解决方案还不错,但是设置 class 的名称很难看,而且类型不能被 pickled。

是否有更好的创建动态 ctype 的方法class?

注:我用的是Python2.7

解决方案 2 可能是更好的选择,但如果您还静态地编写这样的 类,您可能希望使用元类来删除部分代码的重复数据。如果您需要您的对象是可腌制的,那么您将需要一种方法来从可腌制对象中重建它们。一旦你实现了这样的机制,你可以使用 a __reduce__() method.

让 pickle 模块知道它

我会选择解决方案 1 的变体。与其评估代码,不如创建一个带有 __init__.py 的目录(即一个包),将其添加到您的 sys.path 并写出整个python 模块包含所有 类。然后你可以从一个稳定的命名空间导入它们,这会让 pickle 更快乐。

您可以获取输出并将其添加到应用程序的源代码中,或者动态重新创建它并在运行时将其缓存在目标机器上。

pywin32 使用类似这样的方法来缓存从 ActiveX 接口生成的 类。