在C++中导入用SWIG包装的Python模块的正确方法是什么?

2024-04-19 00:48:47 发布

您现在位置:Python中文网/ 问答频道 /正文

使用swig创建python模块是最简单的部分。 但是,如果这个模块必须与我的C++应用程序交互,将其从其嵌入式Python实例中导入?p>

例如@flex在如何向应用程序公开python模块方面提供了一个很好的示例:How can I implement a C++ class in Python, to be called by C++?

我想要的是应用程序和模块能够相互交互,比如共享变量和调用回调等等,所以我发现这个答案对于任务来说有点太复杂了。 关于如何实现这一点,我真的找不到太多其他的东西,swig文档也没有解释这一点(我想它更多地与python有关,而不是与swig有关,这就是为什么swig文档中没有提到它的原因)

我发现,我也可以只包括在我C++应用程序中使用SWIG创建的*yWrAP.cxx文件,并获得相同的结果(见下面的代码)

我刚从SWIG和Python开始,这就是为什么我现在的问题是,有没有比我更好的方法或官方方法来实现相同的结果?我忽略了什么吗?
我是否可以在初始化python实例之前导入swig模块,而不必包含Swigtest_wrap.cxx文件?


我就是这样做的:

一,。档案

以下三个文件包含python模块所需的所有内容。只包含一个类,稍后我想将其用作新python类的基类

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;
}

i-SWIG的接口文件

这里唯一需要注意的是“director”功能的激活

%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"

Switest.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

main.cpp

#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();
}

二,。建筑

构建模块

#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

三,。执行:

从终端启动应用程序

$ ./libmyapp.so

输出

callback not set
this class was created in python - It worked!

就这样


Tags: 模块thetoin应用程序includecallbackour