python - Python C-Api……如何从 C 创建一个“IntEnum”对象
问题描述
我想使用 示例中的 Tcl-C-Code作为模板在C中创建一个名为MqHandShakeE的IntEnum子类
int NS(Get_MqHandShakeE_FromObj) (Tcl_Interp *interp, Tcl_Obj *enumE, enum MqHandShakeE *ret) {
int index;
const static struct LookupEnumE keys[] = {
{ "START", MQ_HANDSHAKE_START },
{ "OK", MQ_HANDSHAKE_OK },
{ "ERROR", MQ_HANDSHAKE_ERROR },
{ NULL, 0 }
};
TclErrorCheck (Tcl_GetIndexFromObjStruct (interp, enumE, &keys,
sizeof(struct LookupClassS), "enum", TCL_EXACT, &index));
*ret = keys[index].val;
return TCL_OK;
}
我的目标是调用一个 python 函数......</p>
myfunc … MqHandShakeE.OK …
C 常数MQ_HANDSHAKE_START
是一个整数
仅 Python 解决方案:
from enum import IntEnum
class WAIT(IntEnum):
NO = 0
ONCE = 1
FOREVER = 2
这是类型安全的,因为WAIT.NO
具有类型WAIT
和值0
……我可以检查……从下往上的子模块方法不是类型安全的…… WAIT.NO
as 子模块具有类型int
解决方案
在我发布了 C++ 示例后,我意识到 OP 已经用 C(不是 C++)标记了这个问题。对不起,我的错。这是C中的一个示例:
#include <Python.h>
#include <assert.h>
#include <stdio.h>
/* sample enum in C */
enum MQ_HANDSHAKE {
MQ_HANDSHAKE_START,
MQ_HANDSHAKE_OK,
MQ_HANDSHAKE_ERROR
};
/* make Python binding for MQ_HANDSHAKE */
static struct PyModuleDef moduleMQ_HANDSHAKE = {
PyModuleDef_HEAD_INIT,
"MQ_HANDSHAKE", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
* or -1 if the module keeps state in global variables.
*/
NULL /* function table (no functions) */
};
static PyObject* initModuleMQ_HANDSHAKE(void)
{
static PyObject *pSelf = NULL;
if (!pSelf) {
pSelf = PyModule_Create(&moduleMQ_HANDSHAKE);
PyModule_AddObject(pSelf, "START", PyLong_FromLong(MQ_HANDSHAKE_START));
PyModule_AddObject(pSelf, "OK", PyLong_FromLong(MQ_HANDSHAKE_OK));
PyModule_AddObject(pSelf, "ERROR", PyLong_FromLong(MQ_HANDSHAKE_ERROR));
}
return pSelf;
}
/* adds module MQ_HANDSHAKE to Python modules table.
*/
void appendModuleMQ_HANDSHAKE(void)
{
assert(!Py_IsInitialized());
PyImport_AppendInittab("MQ_HANDSHAKE", &initModuleMQ_HANDSHAKE);
}
/* test program */
int main()
{
/* initialize Python extension MQ_HANDSHAKE */
appendModuleMQ_HANDSHAKE();
/* initialize Python interpreter */
Py_Initialize();
/* sample Python program */
static const char *const pyProgram
= "print(\"Hello world (from Python).\")\n"
"\n"
"# import Python extension MQ_HANDSHAKE\n"
"import MQ_HANDSHAKE\n"
"\n"
"# test whether it works\n"
"def printHandshake(value):\n"
" if value == MQ_HANDSHAKE.START:\n"
" print(\"MQ_HANDSHAKE_START\")\n"
" elif value == MQ_HANDSHAKE.OK:\n"
" print(\"MQ_HANDSHAKE_OK\")\n"
" elif value == MQ_HANDSHAKE.ERROR:\n"
" print(\"MQ_HANDSHAKE_ERROR\")\n"
" else:\n"
" print(\"Illegal MQ_HANDSHAKE value!\")\n"
"\n"
"printHandshake(MQ_HANDSHAKE.START)\n"
"printHandshake(MQ_HANDSHAKE.OK)\n"
"printHandshake(MQ_HANDSHAKE.ERROR)\n"
"printHandshake(0)\n"
"printHandshake(1)\n"
"printHandshake(2)\n"
"printHandshake(42)\n";
/* run Python interpreter */
const int ret = PyRun_SimpleString(pyProgram);
if (ret) {
fprintf(stderr, "Execution in PyRun_SimpleString() failed!\n");
}
/* done */
return ret;
}
在 VS2013 中使用 Python 3.6 编译和测试:
Hello world (from Python).
MQ_HANDSHAKE_START
MQ_HANDSHAKE_OK
MQ_HANDSHAKE_ERROR
MQ_HANDSHAKE_START
MQ_HANDSHAKE_OK
MQ_HANDSHAKE_ERROR
Illegal MQ_HANDSHAKE value!
此示例建立了一个模块,该模块MQ_HANDSHAKE
- 必须在调用之前附加到 Python 表(使用PyImport_AppendInittab()
)PyInitialize()
- 必须在 Python 代码中导入(使用import MQ_HANDSHAKE
)。
C++ 代码的原始答案:
我查看了我们的 Python 包装器并为 OPs 案例制作了一个小示例:
#include <Python.h>
#include <cassert>
#include <iostream>
// sample enum in C/C++
enum MQ_HANDSHAKE {
MQ_HANDSHAKE_START,
MQ_HANDSHAKE_OK,
MQ_HANDSHAKE_ERROR
};
namespace Py {
namespace MQ {
// make Python binding for MQ_HANDSHAKE
namespace HANDSHAKE {
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"mq.Handshake", // name of module
nullptr, // module documentation, may be NULL
-1, /* size of per-interpreter state of the module,
* or -1 if the module keeps state in global variables.
*/
nullptr // function table (no functions)
};
static PyObject* init()
{
static PyObject *pSelf = nullptr;
if (!pSelf) {
pSelf = PyModule_Create(&module);
PyModule_AddObject(pSelf, "START", PyLong_FromLong(MQ_HANDSHAKE_START));
PyModule_AddObject(pSelf, "OK", PyLong_FromLong(MQ_HANDSHAKE_OK));
PyModule_AddObject(pSelf, "ERROR", PyLong_FromLong(MQ_HANDSHAKE_ERROR));
}
return pSelf;
}
} // namespace HANDSHAKE
// make module MQ
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"mq", // name of module
nullptr, // module documentation, may be NULL
-1, /* size of per-interpreter state of the module,
* or -1 if the module keeps state in global variables.
*/
nullptr // function table (no functions)
};
// initializes module mq
static PyObject* init()
{
static PyObject *pSelf = nullptr;
if (!pSelf) {
pSelf = PyModule_Create(&module);
PyModule_AddObject(pSelf, "Handshake", HANDSHAKE::init());
}
return pSelf;
}
// adds module mq to Python modules table.
void append()
{
assert(!Py_IsInitialized());
PyImport_AppendInittab("mq", &init);
}
} // namespace MQ
} // namespace Py
// test program
int main()
{
// initialize Python extension mq
Py::MQ::append();
// initialize Python interpreter
Py_Initialize();
// sample Python program
static const char *const pyProgram
= "print(\"Hello world (from Python).\")\n"
"\n"
"# import Python extension mq\n"
"import mq\n"
"\n"
"# test whether it works\n"
"def printHandshake(value):\n"
" if value == mq.Handshake.START:\n"
" print(\"MQ_HANDSHAKE_START\")\n"
" elif value == mq.Handshake.OK:\n"
" print(\"MQ_HANDSHAKE_OK\")\n"
" elif value == mq.Handshake.ERROR:\n"
" print(\"MQ_HANDSHAKE_ERROR\")\n"
" else:\n"
" print(\"Illegal MQ_HANDSHAKE value!\")\n"
"\n"
"printHandshake(mq.Handshake.START)\n"
"printHandshake(mq.Handshake.OK)\n"
"printHandshake(mq.Handshake.ERROR)\n"
"printHandshake(0)\n"
"printHandshake(1)\n"
"printHandshake(2)\n"
"printHandshake(42)\n";
// run Python interpreter
const int ret = PyRun_SimpleString(pyProgram);
if (ret) {
std::cerr << "Execution in PyRun_SimpleString() failed!\n";
}
// done
return ret;
}
在 VS2013 中使用 Python 3.6 编译和测试:
Hello world (from Python).
MQ_HANDSHAKE_START
MQ_HANDSHAKE_OK
MQ_HANDSHAKE_ERROR
MQ_HANDSHAKE_START
MQ_HANDSHAKE_OK
MQ_HANDSHAKE_ERROR
Illegal MQ_HANDSHAKE value!
我必须承认,我通过在我们的生产代码中作弊来模仿这个示例,我们曾经在挖掘在线资源时耐心地做这件事。对于基本介绍,我推荐1. Embedding Python in Another Application。
必须先在 Python 代码中导入根模块,然后才能使用它(import mq
在 Python 示例代码中)。在我们的生产代码中,我们在单独的前面调用 中完成了它PyRun_SimpleString()
,因此我们的 Python 应用程序程序员甚至不需要关心这个。
我将实现拆分为多个模块(mq
和mq.Handshake
)。mqHandshake
通过使用模块变量START
、OK
和建立一个模块,这当然可以更短地完成ERROR
。
推荐阅读
- javascript - 如何清除/重置 react.js 表单中的输入数据?
- arrays - 更新路径会在 mongodb 中产生写入冲突
- java - 按多个字段上的对象列表分组Java 8
- json - 如何在 Laravel 中将空 json 作为 {} 返回
- c++ - 退货不能转换
- python - 有没有办法用 django 显示 jupyter 笔记本
- sql-server - LocalDb 上“PROVIDER”附近的语法不正确
- xpath - Xpath:如何在句子中分别选择第一个和第二个数字
- sql - 按包含/排除/空日期范围限制记录
- r - R dplyr:使用前一行值和函数计算行值