Python C-Api ... как создать объект "IntEnum" из C

Я хочу создать подкласс IntEnum с именем MqHandShakeE в C, используя Tcl-C-код из примера в качестве шаблона

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 - это ЦЕЛОЕ

Единственное решение Python:

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

это типобезопасно, потому что WAIT.NO имеет тип WAIT и значение 0… это я могу проверить… подход субмодуля снизу безопасен по типу нетWAIT.NO как субмодуль имеет тип int

Когда я пишу оболочки Python для нашего кода C++, касающиеся enum, я создаю (под) модуль для каждого enum, а затем добавляю переменные int для соотв. счетчики. (Что-то вроде enum, похоже, не существует в Python.) Может быть, можно было бы подклассифицировать один из встроенных целочисленных типов Python, но трюк с модулем / переменной в нашем случае работает правильно. Следовательно, я никогда не пробовал подклассы.

Scheff's Cat 19.11.2018 08:00

Я тестирую подход субмодуль ... проблема в том ... что это типичный НЕТ

Andreas Otto 22.11.2018 19:31
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
920
2

Ответы 2

После того, как я опубликовал образец для 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. Встраивание Python в другое приложение.

Корневой модуль должен быть импортирован в код Python, прежде чем его можно будет использовать (import mq в примере кода Python). В нашем продуктивном коде мы сделали это в отдельном предыдущем вызове PyRun_SimpleString(), так что нашим программистам приложений Python даже не нужно об этом заботиться.

Я разделил реализацию на несколько модулей (mq и mq.Handshake). Конечно, это можно было бы сделать еще быстрее, установив модуль mqHandshake с переменными модуля START, OK и ERROR.

@AndreasOtto Я упустил из виду тег C. Однако это выглядит очень похоже на C. Я расширил ответ на образец C (реализуя упомянутую альтернативу только с одним модулем).

Scheff's Cat 19.11.2018 13:03

Привет, я тестировал это ... используя> PyModule_AddIntConstant(pSelf, "START", MQ_HANDSHAKE_START), проблема в том ... модуль const имеет тип int, это не улучшение, добавление обычного верхнего уровня> PyModule_AddIntConstant(pSelf, "HANDSHAKE_START)",MQ_HANDSHAKE_START)

Andreas Otto 22.11.2018 19:26

это мой ответ ... создать класс типобезопасныйIntEnum в python-C-api.

Python C-API ... как писать код Python на C

Другие вопросы по теме