Получить доступ к классу C ++, созданному на python, из C ++ - PullRequest
2 голосов
/ 08 ноября 2019

Как это сделать

c++ -> Python -> c++
 ^               |
 |               |
 -----------------
  1. Приложение C ++ поддерживает Python.
  2. Python создает класс, который на самом деле является переносом на объект c / c ++
  3. Как получить доступ с хостинга c ++ к указателю c / c ++ этого объекта, созданного python?

Пример с кодом:

Представьте, что у меня есть класс C ++, обернутый для python (например, с использованием boost.python)

// foo.cpp
#include <boost/python.hpp>

struct Cat {
   Cat (int fur=4): _fur{i} { }
   int get_fur() const { return _fur; }
private:
   int _fur;
};

BOOST_PYTHON_MODULE(foo) {
using namespace boost::python;

class_<Cat>("Cat", init<int>())
   .def("get_fur", &A::get_fur, "Density of cat's fur");

}

Теперь Я размещаю питона на C ++ . Сценарий Python создает Cat => Под ним создается экземпляр C ++ Cat. Как получить указатель на экземпляр C ++ Cat с хостинга c ++ (от C ++ до C ++)?

#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);  /* optional but recommended */
  Py_Initialize();
  PyRun_SimpleString("from cat import Cat \n"
                     "cat = Cat(10) \n");

  // WHAT to do here to get pointer to C++ instance of Cat
   ... ??? ...

  std::cout << "Cat's fur: " << cat->get_fur() << std::endl

  Py_Finalize();
  return 0;
}

Реальное приложение Реальная проблема заключается в следующем: у нас есть фреймворк c ++, который имеетдовольно сложная фаза инициализации и конфигурации, где производительность не критична;и затем этап обработки, где производительность - это все. Для фреймворка есть python-оболочка. Определять вещи в python очень удобно, но запуск из python все еще медленнее, чем чистый код на C ++. По многим причинам заманчиво выполнить этот этап конфигурации / инициализации в python, получить указатели на объекты C ++, а затем запустить в «чистом режиме c ++». Было бы легко, если бы мы могли писать все с нуля, но мы уже в значительной степени определили (30 лет) фреймворк c ++.

Ответы [ 2 ]

1 голос
/ 08 ноября 2019
#include <Python.h>

int main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);
  Py_Initialize();

  object module = import("__main__");
  object space = module.attr("__dict__");

  exec("from cat import Cat \n"
       "cat = Cat(10) \n",
       space);

  Cat& cat = extract<Cat&>(space["cat"]);
  std::cout<<"Cat's fur: "<< cat.get_fur() <<"\n";

  //or:

  Cat& cat2 = extract<Cat&>(space.attr("cat"));
  std::cout<<"Cat's fur: "<< cat2.get_fur() <<"\n";

  //or:

  object result = eval("cat = Cat(10)");
  Cat& cat3 = extract<Cat&>(result);
  std::cout<<"Cat's fur: "<< cat3.get_fur() <<"\n";

  Py_Finalize();
  return 0;
}
0 голосов
/ 08 ноября 2019

Если оболочка имеет открытый исходный код, используйте структуру объекта оболочки Python из C ++. Приведите PyObject * к той структуре, которая должна иметь PyObject в качестве первого члена iirc, и просто получите доступ к указателю на экземпляр C ++.

Убедитесь, что экземпляр не удален во время его использования, сохраняяэкземпляр оболочки вокруг в Python. Когда он будет выпущен, он, вероятно, удалит обернутый экземпляр C ++, на который вы до сих пор держите указатель.

И имейте в виду, что этот подход рискованный и хрупкий, поскольку зависит от деталей реализации оболочки,может измениться в будущих версиях.

Начальная точка: cpython / object.h

...