运行 python 在 C++ 中
Run python in C++
我有一个用 C++ 编写的应用程序和一个测试系统(也是用 C++ 编写的)。测试系统非常复杂并且很难改变(我只想做一些小的改变)。我的 class 看起来像这样:
class Derived : public Base {
public:
void somefunc(const AnotherClass& file) {
}
};
里面有几个函数。我的测试系统创建 Derived class 实例,然后使用它的方法做一些事情。
现在我希望能够在 Python 中编写解决方案。我需要双向集成。我的想法是写Python函数,每次调用somefunc
时都会执行这个函数。而且我不想在 Python 中从一个函数启动到另一个函数丢失变量值。而且我还希望能够使用在 python 的 Base class 实例中定义的方法。我怎样才能实现这些目标?
出于这些目的,我选择了 Boost.Python。现在,我明白了,如何使用 c++ 函数,甚至在 Python 中使用简单的 class 经过一些工作。但我不明白如何从 c++ 启动 Python 函数。
第二个问题 - Boost.Python 是一个好的选择吗?我需要一些非常快速且易于使用的东西。
感谢您的帮助。
我会推荐使用 Cython 来做这类事情。改编自 another question 的示例。 (编辑:根据要求,我添加了一个包含 C++ 的扩展示例 class,请参阅下文。)
编辑: 简单示例,一种方式 (C++ -> Python)。
quacker.py:
def quack():
print("Quack!")
cquacker.pyx:
from quacker import quack
cdef public void cquack():
quack()
main.cpp:
#if _WIN32
#include <direct.h>
#define getcwd _getcwd
#define PATH_SEPARATOR ';'
#else
#include <unistd.h>
#define PATH_SEPARATOR ':'
#endif
#include <iostream>
#include <string>
#include <sstream>
#include <Python.h>
#include "cquacker.h"
std::wstring getSysPath()
{
char cwd[FILENAME_MAX];
getcwd(cwd, FILENAME_MAX);
std::wstringstream path;
path << Py_GetPath() << PATH_SEPARATOR << cwd;
return path.str();
}
int main()
{
Py_Initialize();
PySys_SetPath(getSysPath().c_str());
PyInit_cquacker();
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
cquack();
Py_Finalize();
return 0;
}
编辑: 扩展示例,往返(C++ -> Python -> C++)。
quacker.py:
def qcallback(duck):
duck.quack()
quacker/Duck.hpp
#include <iostream>
namespace quacker {
class Duck
{
public:
void quack() { std::cout << "Quack!" << "\n"; }
};
}
cquacker_defs.pxd:
cdef extern from "quacker/Duck.hpp" namespace "quacker":
cdef cppclass Duck:
Duck() except +
void quack()
cquacker.pyx:
from cython.operator cimport dereference as deref
from libcpp.memory cimport shared_ptr
cimport cquacker_defs
from quacker import qcallback
cdef class Duck:
cdef shared_ptr[cquacker_defs.Duck] _this
@staticmethod
cdef inline Duck _from_this(shared_ptr[cquacker_defs.Duck] _this):
cdef Duck result = Duck.__new__(Duck)
result._this = _this
return result
def __init__(self):
self._this.reset(new cquacker_defs.Duck())
def quack(self):
assert self._this != NULL
deref(self._this).quack()
cdef public void cqcallback(shared_ptr[cquacker_defs.Duck] duck):
qcallback(Duck._from_this(duck))
main.cpp:
#if _WIN32
#include <direct.h>
#define getcwd _getcwd
#define PATH_SEPARATOR ';'
#else
#include <unistd.h>
#define PATH_SEPARATOR ':'
#endif
#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include "quacker/Duck.hpp"
#include <Python.h>
#include "cquacker.h"
std::wstring getSysPath()
{
char cwd[FILENAME_MAX];
getcwd(cwd, FILENAME_MAX);
std::wstringstream path;
path << Py_GetPath() << PATH_SEPARATOR << cwd;
return path.str();
}
int main()
{
Py_Initialize();
PySys_SetPath(getSysPath().c_str());
PyInit_cquacker();
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
auto duck = std::make_shared<quacker::Duck>();
cqcallback(duck);
Py_Finalize();
return 0;
}
我有一个用 C++ 编写的应用程序和一个测试系统(也是用 C++ 编写的)。测试系统非常复杂并且很难改变(我只想做一些小的改变)。我的 class 看起来像这样:
class Derived : public Base {
public:
void somefunc(const AnotherClass& file) {
}
};
里面有几个函数。我的测试系统创建 Derived class 实例,然后使用它的方法做一些事情。
现在我希望能够在 Python 中编写解决方案。我需要双向集成。我的想法是写Python函数,每次调用somefunc
时都会执行这个函数。而且我不想在 Python 中从一个函数启动到另一个函数丢失变量值。而且我还希望能够使用在 python 的 Base class 实例中定义的方法。我怎样才能实现这些目标?
出于这些目的,我选择了 Boost.Python。现在,我明白了,如何使用 c++ 函数,甚至在 Python 中使用简单的 class 经过一些工作。但我不明白如何从 c++ 启动 Python 函数。
第二个问题 - Boost.Python 是一个好的选择吗?我需要一些非常快速且易于使用的东西。
感谢您的帮助。
我会推荐使用 Cython 来做这类事情。改编自 another question 的示例。 (编辑:根据要求,我添加了一个包含 C++ 的扩展示例 class,请参阅下文。)
编辑: 简单示例,一种方式 (C++ -> Python)。
quacker.py:
def quack():
print("Quack!")
cquacker.pyx:
from quacker import quack
cdef public void cquack():
quack()
main.cpp:
#if _WIN32
#include <direct.h>
#define getcwd _getcwd
#define PATH_SEPARATOR ';'
#else
#include <unistd.h>
#define PATH_SEPARATOR ':'
#endif
#include <iostream>
#include <string>
#include <sstream>
#include <Python.h>
#include "cquacker.h"
std::wstring getSysPath()
{
char cwd[FILENAME_MAX];
getcwd(cwd, FILENAME_MAX);
std::wstringstream path;
path << Py_GetPath() << PATH_SEPARATOR << cwd;
return path.str();
}
int main()
{
Py_Initialize();
PySys_SetPath(getSysPath().c_str());
PyInit_cquacker();
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
cquack();
Py_Finalize();
return 0;
}
编辑: 扩展示例,往返(C++ -> Python -> C++)。
quacker.py:
def qcallback(duck):
duck.quack()
quacker/Duck.hpp
#include <iostream>
namespace quacker {
class Duck
{
public:
void quack() { std::cout << "Quack!" << "\n"; }
};
}
cquacker_defs.pxd:
cdef extern from "quacker/Duck.hpp" namespace "quacker":
cdef cppclass Duck:
Duck() except +
void quack()
cquacker.pyx:
from cython.operator cimport dereference as deref
from libcpp.memory cimport shared_ptr
cimport cquacker_defs
from quacker import qcallback
cdef class Duck:
cdef shared_ptr[cquacker_defs.Duck] _this
@staticmethod
cdef inline Duck _from_this(shared_ptr[cquacker_defs.Duck] _this):
cdef Duck result = Duck.__new__(Duck)
result._this = _this
return result
def __init__(self):
self._this.reset(new cquacker_defs.Duck())
def quack(self):
assert self._this != NULL
deref(self._this).quack()
cdef public void cqcallback(shared_ptr[cquacker_defs.Duck] duck):
qcallback(Duck._from_this(duck))
main.cpp:
#if _WIN32
#include <direct.h>
#define getcwd _getcwd
#define PATH_SEPARATOR ';'
#else
#include <unistd.h>
#define PATH_SEPARATOR ':'
#endif
#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include "quacker/Duck.hpp"
#include <Python.h>
#include "cquacker.h"
std::wstring getSysPath()
{
char cwd[FILENAME_MAX];
getcwd(cwd, FILENAME_MAX);
std::wstringstream path;
path << Py_GetPath() << PATH_SEPARATOR << cwd;
return path.str();
}
int main()
{
Py_Initialize();
PySys_SetPath(getSysPath().c_str());
PyInit_cquacker();
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
auto duck = std::make_shared<quacker::Duck>();
cqcallback(duck);
Py_Finalize();
return 0;
}