Python C-Api…如何从C创建“ IntEnum”对象

时间:2018-11-18 19:27:48

标签: python c api

我想使用 Tcl-C代码 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函数。

myfunc … MqHandShakeE.OK …

C常数MQ_HANDSHAKE_START INTEGER

仅Python解决方案:

from enum import IntEnum
class WAIT(IntEnum):
  NO  = 0
  ONCE = 1
  FOREVER = 2

这是类型安全的,因为WAIT.NO具有类型WAIT和值0…这可以检查…从下往下的子模块方法是不是类型安全的…WAIT.NO作为子模块的类型为int

2 个答案:

答案 0 :(得分:1)

发布了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包装器,并为OP案例做了一些示例:

#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代码中(Python示例代码中的import mq)。在我们高效的代码中,我们是在PyRun_SimpleString()的一个单独的先前调用中完成的,因此我们的Python应用程序程序员甚至不需要关心这一点。

我将实现分为多个模块(mqmq.Handshake)。通过使用模块变量mqHandshakeSTARTOK建立模块ERROR,无疑可以做得更短。

答案 1 :(得分:0)

这是我的答案…在python-C-api中创建类型安全 IntEnum 类。

Python C-API… how to write python code in C