C++をpythonで実行した時に関数の戻り値とかってC++側はどうやって入手させよう?
まさかの2日連続投稿。
注意と言う名の宣伝
今回は前回の記事の続きになっているのでまず先にそちらをみることをおすすめします。
インストールは良かったけど...
関数の戻り値とかってC++側はどうやって入手するの? そんなふうに思って検索をしたら、ありましたありました。
As explained before, using PyRun_SimpleString seems to be a bad idea.
訳: 前に説明したように、PyRun_SimpleString
を使用することはあまりいい考えじゃないと思うよ。
なるほどね。それは薄々気付いていたよ。それで?
You should definitely use the methods provided by the C-API (http://docs.python.org/c-api/).
訳: C-APIで提供されるメソッドを使用しなくちゃ考えてることは実現できないよ。 (http://docs.python.org/c-api/).
そうなの?あれちょっと面倒じゃない?
First, import your module
PyObject* myModuleString = PyString_FromString((char*)"mytest"); PyObject* myModule = PyImport_Import(myModuleString);
Then getting a reference to your function
PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs"); PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
Then getting your result
PyObject* myResult = PyObject_CallObject(myFunction, args)
And getting back to a double
double result = PyFloat_AsDouble(myResult);
マジで?天才かよ。
実践
main.cpp
#include <Python.h> #include <iostream> int main() { Py_Initialize(); PyObject* myModuleString = PyUnicode_FromString((char*)"mytest"); PyObject* myModule = PyImport_Import(myModuleString); PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs"); PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0)); PyObject* myResult = PyObject_CallObject(myFunction, args); double result = PyFloat_AsDouble(myResult); std::cout << result << std::endl; Py_Finalize(); return 0; }
mytest.py
import math def myabs(x): return math.fabs(x)
ビルド&実行
$ gcc main.cpp `pkg-config python3 --cflags` -lpython3.8 -lstdc++ $ PYTHONPATH=. ./a.out 2
出典元のプログラムはパスが通っておらず、セグメンテーション違反になってしまったので、実行時にPYTHONPATH=. a.out
でパスを設定してあげている。gccの引数については前回の記事を見てほしい。
C/C++で何もライブラリを使用せずにpythonを動かしてみる。 - kumitatepazuru's blog
最後に
ちょっと面倒だけど、使い方をマスターすれば最強かも...?
個人的な質問等はこちらまで。
https://forms.gle/V6NRhoTooFw15hJdA
また、自分が参加しているRobocup soccer シミュレーションリーグのチームでは参加者募集中です!活動の見学、活動に参加したい方、ご連絡お待ちしております!
詳しくはこちら