C++
 Computer >> コンピューター >  >> プログラミング >> C++

C/C++からPythonオブジェクトを操作する方法(Cython埋め込みの実践ガイド)

C/C++からPythonオブジェクトを使うには?

CやC++のプログラムからPythonオブジェクトを直接生成・操作したい場合、Cythonを利用するのが最も手軽な方法の一つです。ここでは、シンプルなPythonクラスをCythonでラップし、C言語側に組み込んで(埋め込んで)呼び出す例を紹介します。C++の場合も手順はほぼ同じで、コンパイル時に--cplusオプションを付けるだけで対応できます。

ステップ1:Pythonクラスと公開関数を定義する(pycls.pyx)

まず、ラップ対象となるPythonクラスと、C側から呼び出せるようにするためのcdef public関数を定義したファイル「pycls.pyx」を作成します。

class PyClass(object):
    def __init__(self):
        self.data = []
    def add(self, val):
        self.data.append(val)
    def __str__(self):
        return "Data: " + str(self.data)

cdef public object createPyClass():
    return PyClass()

cdef public void addData(object p, int val):
    p.add(val)

cdef public char* printCls(object p):
    return bytes(str(p), encoding='utf-8')

ポイントはcdef publicという宣言です。このキーワードを付けた関数は、Cythonが生成するヘッダファイル(.h)に関数宣言として書き出されるため、外部のCコードから直接呼び出すことが可能になります。

  • createPyClass(): PyClassインスタンスを生成して返します。
  • addData(obj, val): オブジェクトのaddメソッドを経由してデータを追加します。
  • printCls(obj): __str__の結果をUTF-8エンコードのバイト列(char*)として返し、C側でprintfできるようにしています。

ステップ2:Cythonでコンパイルして.cファイルと.hファイルを生成

次のコマンドでCythonコンパイルを行います。C言語向けならそのまま、C++向けには--cplusフラグを追加してください。

cython pycls.pyx          # C言語用
cython --cplus pycls.pyx  # C++用

これにより、実装本体であるpycls.cと、関数宣言を含むpycls.hが生成されます。

ステップ3:Pythonインタプリタを初期化するmain.cを作成

C側のメインプログラムでは、まずPythonインタプリタを初期化し、続いてモジュールを初期化してから各関数を呼び出します。

#include "Python.h"   // Python.hは必ず最初にインクルードする
#include "pycls.h"    // 自分のヘッダファイル

int main(int argc, char *argv[]){
    Py_Initialize();   // Pythonインタプリタを初期化
    PyInit_pycls();    // モジュールを初期化(Python 2では initpycls(); )

    PyObject *obj = createPyClass();
    for(int i=0; i<10; i++){
        addData(obj, i);
    }
    printf("%s\n", printCls(obj));

    Py_Finalize();     // Pythonインタプリタを終了
    return 0;
}

処理の流れは以下の通りです。

  1. Py_Initialize()でPythonインタプリタを起動。
  2. PyInit_pycls()でモジュールを読み込み、クラス定義を有効化。
  3. createPyClass()でオブジェクトを生成し、ループで0〜9の値を追加。
  4. printCls()でオブジェクトの中身を文字列として表示。
  5. Py_Finalize()でインタプリタを終了。

ステップ4:ビルドと実行

最後に、Pythonの設定情報を取得しながらgccでリンクします。python3.5-config(Python 2の場合はpython-config)を使うと、必要なインクルードパスやライブラリフラグを自動的に取得できます。

gcc pycls.c main.c $(python3.5-config --cflags) $(python3.5-config --ldflags) -std=c99 -o pyembed

生成された実行ファイルを実行すると、Cプログラム内でPythonオブジェクトが正しく動作していることが確認できます。

./pyembed
Data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

まとめ

このように、Cythonのcdef publicキーワードを使えば、Pythonオブジェクトを操作するための関数が自動的にヘッダファイルへ書き出され、C/C++側から透過的に呼び出せるようになります。Pythonの豊富なライブラリや柔軟なデータ構造を、高速なC/C++アプリケーションから活用したい場合に非常に有効な手法なので、ぜひ試してみてください。

  1. PythonのTkinterでスレッドを使う方法|threadingモジュールによる非同期処理の基本

    Tkinterでは、スレッド(Threading)を活用することで、複数の関数を同時に実行できます。これにより、アプリケーション内の処理を非同期で動かすことが可能になります。 Pythonでスレッドを使用するには、まずthreadingモジュールをインポートし、そのThreadクラスを継承した新しいクラスを定義します。そして、クラス内でrunメソッドをオーバーライドし、実行したい処理をその中に記述します。 つまり、スレッドを使えば複数の作業を並行して進めることができます。Tkinterアプリケーションでスレッドを実現する際は、Thread()関数を利用します。 ここでは、「一定時間スリープした

  2. MacでPythonを始める方法|インストールから初めてのコード実行まで徹底解説

    プログラミング学習は今や世界的なブームとなっており、その中でもPythonは初心者にとって最適な言語のひとつです。幸いなことに、Macは優れたコーディングプラットフォームであり、Pythonとの相性も抜群。Mac上で快適にプログラミングを学ぶことができます。 この記事では、macOSへのPythonのセットアップ方法から、実際にコードを書いて動かすところまでを詳しく解説します。Pythonの学習曲線は非常に緩やかで、すでにお使いのMacにPythonがインストールされている可能性もあります(インストールされていない場合もご安心ください。導入手順も紹介します)。 ここではPythonに焦点を当て