Python が C++ プログラムを呼び出す方法の詳細な説明

高洛峰
リリース: 2017-02-20 10:28:28
オリジナル
1451 人が閲覧しました

はじめに

Python の利点は高い開発効率と使いやすさであり、C++ は高い操作効率を持っていることは誰もが知っています。C++ コードを Python プロジェクトに埋め込む場合でも、Python プロジェクトに埋め込む場合でも、この 2 つは相互に補完し合うことができます。 C++ プロジェクト Python を使用して周辺機能を実装する場合、Python で C++ モジュールを呼び出す必要がある場合があります。集中化された C++ コードを Python インターフェイスにエクスポートするためのいくつかの基本的な方法を紹介します。

オリジナルのエクスポート

Python インタープリターは C で実装されているため、C++ データ構造が Python で理解できる限り、理論的には直接呼び出すことができます。 test1.cppは以下のように実装します

#include <Python.h>

int Add(int x, int y)
{
 return x + y;
}

int Del(int x, int y)
{
 return x - y;
}

PyObject* WrappAdd(PyObject* self, PyObject* args)
{
 int x, y;
 if (!PyArg_ParseTuple(args, "ii", &x, &y))
 {
  return NULL;
 }
 return Py_BuildValue("i", Add(x, y));
}

PyObject* WrappDel(PyObject* self, PyObject* args)
{
 int x, y;
 if (!PyArg_ParseTuple(args, "ii", &x, &y))
 {
  return NULL;
 }
 return Py_BuildValue("i", Del(x, y));
}
static PyMethodDef test_methods[] = {
 {"Add", WrappAdd, METH_VARARGS, "something"},
 {"Del", WrappDel, METH_VARARGS, "something"},
 {NULL, NULL}
};

extern "C"
void inittest1()
{
 Py_InitModule("test1", test_methods);
}
ログイン後にコピー

コンパイルコマンドは以下の通りです

g++ -fPIC -shared test1.cpp -I/usr/include/python2.6 -o test1.so
ログイン後にコピー

Pythonインタプリタを実行して以下のようにテストします

>>> import test1
>>> test1.Add(1,2)
3
ログイン後にコピー

ここに注意してください

  1. 生成されたダイナミックライブラリの名前がtest1の場合、ソースファイルにはinittest1関数が必要で、Py_InitModuleの最初のパラメータは「test1」である必要があります。そうしないと、Pythonインポートモジュールは失敗します

  2. cpp ソースファイルの場合、inittest1 extern "C" で関数を変更する必要があります。 c ソース ファイルの場合、必要ありません。その理由は、Python インタープリターはライブラリをインポートするときに initxxx のような関数を検索し、C と C++ は関数シンボルをエンコードするときに関数の長さとパラメーターの型を異なる方法で考慮するためです。具体的には、 nm test1 を渡すことができます。 .so関数シンボルを表示します。c++filt ツールはシンボルを通じて関数プロトタイプをデコードできますnm test1.so查看函数符号,c++filt工具可通过符号反解出函数原型

通过boost实现

我们使用和上面同样的例子,实现test2.cpp如下

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;

int Add(const int x, const int y)
{
 return x + y;
}

int Del(const int x, const int y)
{
 return x - y;
}

BOOST_PYTHON_MODULE(test2)
{
 def("Add", Add);
 def("Del", Del);
}
ログイン後にコピー

其中BOOST_PYTHON_MODULE的参数为要导出的模块名字

编译命令如下

g++ test2.cpp -fPIC -shared -o test2.so -I/usr/include/python2.6 -I/usr/local/include -L/usr/local/lib -lboost_python
ログイン後にコピー

注意: 编译时需要指定boost头文件和库的路径,我这里分别是/usr/local/include和/usr/local/lib

或者通过setup.py导出模块

#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension

setup(name="PackageName",
 ext_modules=[
  Extension("test2", ["test2.cpp"],
  libraries = ["boost_python"])
 ])
ログイン後にコピー

Extension的第一个参数为模块名,第二个参数为文件名

执行如下命令

python setup.py build
ログイン後にコピー

这时会生成build目录,找到里面的test2.so,并进入同一级目录,验证如下

>>> import test2
>>> test2.Add(1,2)
3
>>> test2.Del(1,2)
-1
ログイン後にコピー

导出类

test3.cpp实现如下

#include <boost/python.hpp>
using namespace boost::python;

class Test
{
public:
 int Add(const int x, const int y)
 {
  return x + y;
 }

 int Del(const int x, const int y)
 {
  return x - y;
 }
};

BOOST_PYTHON_MODULE(test3)
{
 class_<Test>("Test")
  .def("Add", &Test::Add)
  .def("Del", &Test::Del);
}
ログイン後にコピー

注意:BOOST_PYTHON_MODULE里的.def使用方法有点类似Python的语法,等同于

class_<Test>("Test").def("Add", &Test::Add);
class_<Test>("Test").def("Del", &Test::Del);
ログイン後にコピー

编译命令如下

g++ test3.cpp -fPIC -shared -o test3.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python
ログイン後にコピー

测试如下

>>> import test3
>>> test = test3.Test()
>>> test.Add(1,2)
3
>>> test.Del(1,2)
-1
ログイン後にコピー

导出变参函数

test4.cpp实现如下

#include <boost/python.hpp>
using namespace boost::python;

class Test
{
public:
 int Add(const int x, const int y, const int z = 100)
 {
  return x + y + z;
 }
};

int Del(const int x, const int y, const int z = 100)
{
 return x - y - z;
}

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(Add_member_overloads, Add, 2, 3)
BOOST_PYTHON_FUNCTION_OVERLOADS(Del_overloads, Del, 2, 3)

BOOST_PYTHON_MODULE(test4)
{
 class_<Test>("Test")
  .def("Add", &Test::Add, Add_member_overloads(args("x", "y", "z"), "something"));
 def("Del", Del, Del_overloads(args("x", "y", "z"), "something"));
}
ログイン後にコピー

这里Add和Del函数均采用了默认参数,Del为普通函数,Add为类成员函数,这里分别调用了不同的宏,宏的最后两个参数分别代表函数的最少参数个数和最多参数个数

编译命令如下

g++ test4.cpp -fPIC -shared -o test4.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python
ログイン後にコピー

测试如下

>>> import test4
>>> test = test4.Test()
>>> print test.Add(1,2)
103
>>> print test.Add(1,2,z=3)
6
>>> print test4.Del(1,2)
-1
>>> print test4.Del(1,2,z=3)
-1
ログイン後にコピー

导出带Python对象的接口

既然是导出为Python接口,调用者难免会使用Python特有的数据结构,比如tuple,list,dict,由于原生态方法太麻烦,这里只记录boost的使用方法,假设要实现如下的Python函数功能

def Square(list_a)
{
 return [x * x for x in list_a]
}
ログイン後にコピー

即对传入的list每个元素计算平方,返回list类型的结果

代码如下

#include <boost/python.hpp>

boost::python::list Square(boost::python::list& data)
{
 boost::python::list ret;
 for (int i = 0; i < len(data); ++i)
 {
  ret.append(data[i] * data[i]);
 }

 return ret;
}

BOOST_PYTHON_MODULE(test5)
{
 def("Square", Square);
}
ログイン後にコピー

编译命令如下

g++ test5.cpp -fPIC -shared -o test5.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python
ログイン後にコピー

测试如下

>>> import test5
>>> test5.Square([1,2,3])
[1, 4, 9]
ログイン後にコピー

boost实现了boost::python::tuple, boost::python::list, boost::python::dict这几个数据类型,使用方法基本和Python保持一致,具体方法可以查看boost头文件里的boost/python/tuple.hpp及其它对应文件

另外比较常用的一个函数是boost::python::make_tuple()

boost を通じて実装されています

🎜🎜🎜上記と同じ例を使用します、次のようにtest2.cppを実装します🎜🎜🎜
boost::python::tuple(int a, int b, int c)
{
 return boost::python::make_tuple(a, b, c);
}
ログイン後にコピー
🎜🎜🎜BOOST_PYTHON_MODULEのパラメータはエクスポートするモジュールの名前です🎜🎜コンパイルコマンドは次のとおりです🎜🎜🎜rrreee🎜🎜🎜🎜🎜注:🎜🎜が必要ですコンパイル時にブースト ヘッダー ファイルとライブラリを指定します。ここでのパスは /usr/local/include および /usr/local/lib🎜🎜 または setup.py を通じてモジュールをエクスポートします🎜🎜🎜rrreee🎜🎜🎜 Extension の最初のパラメータはモジュール名、第二引数 ファイル名に対して以下のコマンドを実行🎜🎜🎜🎜🎜rrreee🎜🎜🎜ビルドディレクトリが生成されるので、その中にあるtest2.soを見つけて同じレベルのディレクトリに入り、以下のように確認してください🎜🎜🎜 rrreee🎜🎜🎜Export class🎜🎜🎜test3 .cpp の実装は次のとおりです🎜🎜🎜rrreee🎜🎜🎜🎜🎜注: 🎜🎜BOOST_PYTHON_MODULE での .def の使用法は Python 構文に似ており、これは次と同等です。 🎜🎜 🎜rrreee🎜🎜🎜コンパイルコマンドは以下の通り🎜🎜🎜rrreee🎜🎜🎜テストは以下の通り🎜🎜🎜rrreee🎜🎜🎜🎜🎜変数パラメータ関数のエクスポート🎜🎜🎜🎜🎜test4.cpp次のように実装されます🎜🎜🎜rrreee 🎜🎜🎜ここでは、Add 関数と Del 関数の両方がデフォルトのパラメーターを使用します。Del は通常の関数で、Add はクラスのメンバー関数です。ここでは異なるマクロが呼び出されます。マクロの最後の 2 つのパラメーターは、パラメーターの最小数と最大数を表します。コンパイルコマンドは以下の通りです🎜🎜🎜rrreee🎜🎜🎜 テストは以下の通りです🎜🎜🎜rrreee🎜🎜 🎜🎜🎜Pythonオブジェクトとのインターフェースをエクスポートします🎜🎜🎜🎜🎜 Python インターフェイスを使用すると、呼び出し元は必然的にタプル、リスト、辞書などの Python 固有のデータ構造を使用することになります。独自のエコロジー手法は面倒なので、ここではブーストのみを記録します。使い方は、次の Python を実装するとします。関数🎜🎜🎜rrreee🎜🎜🎜、つまり、渡されたリストの各要素の二乗を計算し、リスト型の結果を返します🎜🎜コードは次のとおりです🎜🎜🎜rrreee🎜🎜🎜コンパイルコマンドは次のとおりです🎜 🎜🎜rrreee🎜🎜🎜テストは次のとおりです🎜🎜🎜rrreee🎜🎜🎜boostはboost::python::tupleboost::python::listを実装します。 boost::python::dictこれらのデータ型の使用方法は基本的に Python と一致しており、特定の方法については、boost ヘッダー ファイル内の boost/python/tuple.hpp およびその他の対応するファイルを参照できます。 🎜🎜さらによく使用される関数の 1 つは boost::python::make_tuple() です。使用方法は次のとおりです🎜🎜🎜rrreee🎜🎜🎜 Python の呼び出し方法の詳細については、こちらをご覧ください。 C++ プログラムの場合は、PHP 中国語 Web サイトに注意してください。 🎜
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!