(コード付き) はじめに | C/C++ を使用して Python スクリプトを呼び出す方法

編集者のおすすめ

C/C++ を開発する場合、多くの非コア関数は Python を使用して実装できるため、C/C++ プログラムで Python プログラムを呼び出す方法を学ぶことも必要です。これを実現するにはさまざまな方法がありますが、今日は私が最も便利だと思う方法を紹介します。

C/C++言語以外のプログラミング言語 Pythonを組み込むことでC/C++アプリケーションプログラムを強化し、本来のプログラムの機能を変えずにPythonを利用できるようにする方法(Python/C API)を紹介します。アプリケーションの一部の機能を実装します。

このアプローチはいくつかの目的に使用できます。主な目的は、Python でいくつかのスクリプトを作成することで、ニーズに応じてアプリケーションをカスタマイズできるようにすることです (特定の関数は Python でより簡単に作成できます)。Python を埋め込む場合、メイン プログラムは通常、Python 実装とは何の関係もありません。また、アプリケーションの一部は、作成した Python コードを実行するために必要な場合に Python インタープリタを呼び出します。したがって、Python を組み込む必要がある場合は、まず C/C++ メイン プログラムが必要です。

基本的な使い方

Python は C API ライブラリのセットを提供するため、開発者は C/C++ プログラムから Python モジュールを簡単に呼び出すことができます。C++ ユーザーは、API が完全に C で定義されているにもかかわらず、ヘッダー ファイルでエントリ ポイントが extern "C" として宣言されていることに注意してください。したがって、この API を C++ で使用するために API は特別なことを行う必要はありません。

ここに画像の説明を挿入
特定のドキュメントについては、公式ガイドを参照してください: https://docs.python.org/3.9/extending/embedding.html

この API セットを使用する必要がある場合は、Cmake ビルドを例としてヘッダー ファイルとライブラリ ファイルを導入する必要があり、CMakeLists.txt に追加する必要があります。

find_package (Python COMPONENTS Interpreter Development REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${Python_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE ${Python_LIBRARIES})

Windows 環境では、次の 2 つの環境変数が存在することを確認する必要があります (まだテストされていません)。

ここに画像の説明を挿入
次に、対応するヘッダー ファイルを main.cpp に導入できます。

#include <Python.h>

その後、メイン プログラムが行うことの 1 つは、Python インタープリターの初期化です。

Py_Initialize();

もちろん、インタプリタは C 言語で記述できるコードとして初期化する必要があるため、通常は (不要な場合に) 解放する必要があります。

Py_Finalize();

これで、実行したい Python ステートメントを文字列として Python インタープリターに渡すことができます。

PyRun_SimpleString("print("Hello world!")");

シンプルな栗を与える

このメソッドには値を転送する方法がありません(文字列に変換することは当面考えていません。結局のところ、データを同時に受け取るのは面倒であり、これも大きな問題です)。

1. Python インタープリターを初期化する;
2. コードを文字列の形式で渡す;
3. Python インタープリターを解放する。

コードは以下のように表示されます。

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int, char **)
{
    
    
    Py_Initialize();                                       // 初始化python解释器
    PyRun_SimpleString("import matplotlib.pyplot as plt"); // 运行python代码
    PyRun_SimpleString("plt.plot([1,2,3,4], [12,3,23,231])");
    PyRun_SimpleString("plt.show()");
    Py_Finalize(); // 释放python解释器
};

結果は次のとおりです。

ここに画像の説明を挿入
明らかに、C++ プログラムで Python を正常に呼び出し、イメージを描画して表示します。

一般的なデータ型

Python には「すべてはオブジェクトである」という格言がありますが、これはソース コードと組み合わせるとよりよく理解できます。
Python では、すべての変数、関数、クラスなどがインタープリターで実行されると、新しいオブジェクトがヒープに作成され、名前がオブジェクトにバインドされます。

C/C++ では、すべての Python 型は PyObject として宣言されます。Python データを操作できるようにするために、Python はさまざまなデータ型と C 言語のデータ型の間の変換操作を提供します。

PyObject *object;  // 创建python的object的指针
Py_DECREF(object); // 销毁object

1. 数値と文字列の処理
Py_BuildValue() 関数は、数値と文字列を Python の対応するデータ型に変換するために Python/C API で提供されています。

PyObject* Arg = Py_BuildValue("(i, i)", 1, 2);  //i表示创建int型变量

2. リスト操作
PyList_New() 関数は、新しい Python リストを作成するために Python/C API で提供されています。PyList_New() 関数の戻り値は作成されたリストです。

3. タプル操作
PyTuple_New() 関数は、新しい Python タプルを作成するために Python/C API で提供されています。PyTuple_New() 関数は、作成されたタプルを返します。

4. 辞書操作
新しい辞書を作成するための PyDict_New() 関数が Python/C API で提供されています。PyDict_New() 関数は、作成された辞書を返します。

5. cv::Mat 操作
cv::Mat はよく使用する形式です。参照コードは次のとおりです。

PyObject *cvmat2py(cv::Mat &image)
{
    
    
    import_array();
    int row, col;
    col = image.cols; //列宽
    row = image.rows; //行高
    int channel = image.channels();
    int irow = row, icol = col * channel;
    npy_intp Dims[3] = {
    
    row, col, channel}; //图像维度信息
    PyObject *pyArray = PyArray_SimpleNewFromData(channel, Dims, NPY_UBYTE, image.data);
    PyObject *ArgArray = PyTuple_New(1);
    PyTuple_SetItem(ArgArray, 0, pyArray);
    return ArgArray;
}

詳しい操作については、https://docs.python.org/zh-cn/3/c-api/arg.html#building-values を参照してください。

もう少し複雑な栗を取り上げます

このメソッドは値を転送できます。

1. Python インタープリターを初期化する;
2. データを C++ から Python に変換する;
3. 変換されたデータをパラメーターとして使用して Python 関数を呼び出す;
4. 関数の戻り値を C++ データ構造に変換する;
5. Python インタープリターを解放する。

C++ コードは次のとおりです。


#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <iostream>

int main(int, char **)
{
    
    
    // 初始化python解释器
    Py_Initialize();
    if (!Py_IsInitialized())
    {
    
    
        return -1;
    }

    // 添加编译后文件的所在路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");

    // 要调用的python文件名
    auto pModule = PyImport_ImportModule("common"); // 记得复制到编译后文件的路径下,同时不用加后缀名“.py“
    if (!pModule)
    {
    
    
        std::cout << "Can't find your xx.py file.";
        getchar();
        return -1;
    }

    //获取模块中的函数
    auto pFunc = PyObject_GetAttrString(pModule, "add"); //从字符串创建python函数对象

    // 参数类型转换
    PyObject *pArg = Py_BuildValue("ii", 1, 2);

    //调用直接获得的函数,并传递参数
    auto *py_result = PyEval_CallObject(pFunc, pArg);

    int c_result;
    // 将python类型的返回值转换为C类型
    PyArg_Parse(py_result, "i", &c_result);
    std::cout << "return: " << c_result << std::endl;
};

Python コードは次のとおりです (common.py という名前)。

def add(a, b):
    print('a: ', a)
    print('b: ', b)
    return a + b

結果は次のようになります (コード内で設定された Python ファイル検索パスはコンパイルされたファイル パスです)。

ここに画像の説明を挿入
このようにして、2 つの比較的単純な実装が完了しました。その他の操作については、https://docs.python.org/3.9/c-api/index.html#c-api-index を参照してください。

参考文献

1.https://blog.csdn.net/pipisorry/article/details/49532341
2.https://blog.csdn.net/qq_45401419/article/details/123562089
3.https://zhuanlan.zhihu.com/ p/146874652

おすすめ

転載: blog.csdn.net/weixin_41006390/article/details/126191970
おすすめ