如何从C扩展返回Python枚举(Enum)?

4

我正在为Python编写一个C扩展,它包装了一个C库。这个C库有几个枚举类型,我已经分别为它们编写了相应的IntEnum,例如:

from enum import IntEnum
# _enum_consts is a C extension creating Python
# constants for the library's enum constants
from . import _enum_consts

class Align(IntEnum):
    DEFAULT = _enum_consts.MD_ALIGN_DEFAULT
    LEFT = _enum_consts.MD_ALIGN_LEFT
    CENTER = _enum_consts.MD_ALIGN_CENTER
    RIGHT = _enum_consts.MD_ALIGN_RIGHT

现在,在我包装库的主要功能的C扩展中,一些库函数返回枚举类型,并且我想将它们转换为Python的IntEnum值。(我意识到我可以直接返回整数,并且它们将成功地与IntEnum进行比较,但这有点失去了用途。)
问题是,我该如何创建要返回的IntEnum值?我只能找到将C中的枚举常量转换为Python常量的示例,并使用PyModule_AddIntConstant()(这正是_enum_consts扩展模块所做的)。
1个回答

2

首先,需要将带有IntEnum的模块导入到扩展模块中(如果您还没有这样做)。在模块初始化函数中:

PyMODINIT_FUNC PyInit_someextension(void)
{
    // ...

    PyObject *m;
    m = PyModule_Create(&someextension_module);
    if (m == NULL) {
        return NULL;
    }

    // ...

    // Import the enums module, where "somepackage.enums"
    // is the full name of the enums module
    PyObject *enums = PyImport_ImportModule("somepackage.enums");
    if (enums == NULL) {
        Py_DECREF(m);
        return NULL;
    }
    Py_DECREF(enums);

    return m;
}

然后,在您想要实例化 IntEnum 值的地方,首先再次获取它所在的模块:

PyObject *enums = PyImport_AddModule("somepackage.enums");
if (enums == NULL) {
    // Return NULL, -1, etc. to signal an exception
}

紧接着,从模块中获取您的IntEnum类型(在本例中为Align):

PyObject *align_enum = PyObject_GetAttrString(enums, "Align");
if (align_enum == NULL) {
    // Return NULL, -1, etc. to signal an exception
}

然后,您可以创建所需的实例。这里的align将是从IntEnum中获取的值。我们通过调用类型对象来实现这一点,就像在常规Python中一样(请注意,PyObject_CallFunction不仅限于调用函数--它可以调用任何可调用对象):

PyObject *align_instance = PyObject_CallFunction(align_enum, "(i)", align);
if (align_instance == NULL) {
    Py_DECREF(align_enum);
    // Return NULL, -1, etc. to signal an exception
}

现在,align_instance 包含要返回的 IntEnum 实例。在返回之前,请确保 Py_DECREF(align_enum)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接