python - 在 c++ 中导入用 swig 包装的 python 模块的正确方法是什么
问题描述
用 swig 创建一个 python 模块是很容易的部分。但是,如果这个模块必须与我的 C++ 应用程序交互,而我的 C++ 应用程序是从它的嵌入式 python 实例中导入它的呢?
例如,@Flexo 就如何在此处向应用程序公开 python 模块做了一个很好的示例:如何在 Python 中实现 C++ 类,由 C++ 调用?
我想要的是应用程序和模块能够相互交互,比如共享变量和调用回调等等,所以我发现这个答案对于任务来说有点太复杂了。关于如何实现这一点,我真的找不到太多其他的东西,swig 文档也没有解释这一点(我想它更多地与 python 而不是 SWIG 尤其是这就是为什么 SWIG 文档中没有提到它) .
然后我发现我也可以在我的 C++ 应用程序中包含由 SWIG 创建的 *_wrap.cxx 文件并获得相同的结果(参见下面的代码)
我刚开始使用 SWIG 和 Python,这就是为什么我现在的问题是,有没有比我更好的方法或官方方法来实现相同的结果?我忽略了什么吗?
我可以在初始化 python 实例之前导入我的 swig 模块而不必包含 Swigtest_wrap.cxx 文件吗?
我就是这样做到的:
1. 文件
以下三个文件包含我的 python 模块所需的一切。仅包含一个类,我稍后想将其用作新 python 类的基类。
Swigtest.h - python 模块的头文件
#ifndef SWIGTEST_H
#define SWIGTEST_H
class Callback
{
public:
Callback(){}
virtual ~Callback() {}
// we want to override this function in python
virtual void Exec() {}
static void callFunc();
static void setCallback(Callback* callback);
private:
static Callback* m_callback;
};
#endif // SWIGTEST_H
Swigtest.cpp - 用于 python 模块
Callback* Callback::m_callback = nullptr;
void Callback::callFunc()
{
if(m_callback != nullptr)
{
m_callback->Exec();
return;
}
std::cout << "callback not set" << std::endl;
}
void Callback::setCallback(Callback* callback)
{
m_callback = callback;
}
Swigtest.i - SWIG 的接口文件
这里唯一需要注意的是“导演”功能的激活
%module(directors="1") mymodule
// We need to include Swigtest.h in the SWIG generated C++ file
%{
#include <iostream>
#include "Swigtest.h"
%}
// Enable cross-language polymorphism in the SWIG wrapper.
%feature("director") Callback;
// Tell swig to wrap everything in Swigtest.h
%include "Swigtest.h"
最快捷的.py
这个 python 脚本创建了一个从我们的回调类派生的新类,并将回调设置为这个类。
import mymodule
# lets create a new class derived from callback
class MyPyCallbackFromC(mymodule.Callback):
def Exec(self):
print("this class was created in python - It worked!")
callback = mymodule.Callback()
mycallback = MyPyCallbackFromC()
# set callback to this new class
callback.setCallback(mycallback)
# now lets call it from our c++ application
主文件
#include <Python.h>
#include <iostream>
#include "Swigtest.h"
// we include this file to be able to append the python
// module table with our own swig wrapped module
#include "Swigtest_wrap.cxx"
int main()
{
// *_wrap.cxx has to be included for PyInit__mymodule;
// must be added before the Python instance is initialized!
PyImport_AppendInittab("_mymodule", PyInit__mymodule);
Py_Initialize();
// create Callback class
Callback* callback = new Callback();
// call Exec() function of linked class
// should return error because no class is set as Callback yet
callback->callFunc();
// execute our script which sets a new class as our callback
FILE* fp;
const char* filename;
filename = "Swigtest.py";
fp = _Py_fopen(filename, "r");
PyRun_SimpleFile(fp, filename);
// if we now call the callback from our application
// the Exec function that was defined in our python script should be executed
callback->callFunc();
delete callback;
Py_Finalize();
}
2. 建筑
构建模块
#swig
swig -c++ -python Swigtest.i
#compile
g++ -fpic -c Swigtest.cpp Swigtest_wrap.cxx -I/pathTo/python
#build
g++ -Wall -Wextra -shared Swigtest.o Swigtest_wrap.o -o _mymodule.so
构建应用程序
#compile
g++ -fpic -c Swigtest.cpp
g++ -fpic -c main.cpp -I/pathTo/python
#build
g++ main.o Swigtest.o -o libmyapp.so -I/pathTo/python -lpython3
3.执行:
从终端启动应用程序
$ ./libmyapp.so
输出
callback not set
this class was created in python - It worked!
而已。
解决方案
推荐阅读
- javascript - 如何使用 InnerHTML 将 html 类替换为脚本?
- java - 在 android studio 的 Calculator App 中删除 double 的问题?
- haskell - 如何在得到结果之前永久重试 IO?
- ios - 从回调函数 SWIFT 存储数据
- python - 将 timedelta[64] 列转换为从午夜开始的秒数
- c# - PdfStamper 未添加新文本以辅助 PDF
- docker - 从 sudo minikube start --vm-driver none 切换到 --vm-driver docker 并且无法再访问我的应用程序
- database - Laravel Eloquent:在单个数据库事务中保存模型和关系
- javascript - 滚动到下一个(无论 ID)
- python - FastICA 形状未与正常值对齐