Execute Python code on C ++ (using Boost.Python)

Introduction

Boost.Python is often used when creating a library for Python using C ++, but it can also be used for so-called "embedding" that uses Python code from the C ++ side.

Isn't there much demand for using Python code from C ++? Even if you search for "boost python" etc., you will only get articles about the opposite use (when using C ++ code from Python). In that case, including the search keyword "embed" makes it easier to hit articles when embedding Python in C ++.

The simplest code example

main.cpp


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

int main()
{
    Py_Initialize(); //Must be called first

    try
    {
        //In Python "print('Hello World!')Execute
        py::object global = py::import("__main__").attr("__dict__");
        py::exec("print('Hello World!')", global);
    }
    catch (const py::error_already_set &)
    {
        //If an error occurs while executing Python code, the error content is displayed.
        PyErr_Print();
    }

    return 0;
}

In this sample, the py :: exec () function is used to simply execute the Python code print ('Hello World!'). I'm running my code in the global namespace on Python by getting an object in the global namespace on Python in a variable called global.

Boost.Python calls Python's C interface behind the scenes, so you need to call the Py_Initialize () function before using it. (* According to the official tutorial, Py_Finalize () should not be called in the code)

Also, if a runtime error occurs in Python, an exception of type py :: error_already_set will be thrown, so catch this and display the contents withPyErr_Print ().

Compile method (for Linux + GCC)

For Linux + GCC, you can compile with the following command.

How to compile


$ g++ main.cpp `pkg-config python3-embed --cflags --libs` -lboost_python38

Depending on the environment, there may be a version without python3-embed, so change it to pkg-config python3 as appropriate (in the version with python3-embed, the library for embedding is excluded from the original So using pkg-config python3 may result in a link error).

Also, the boost_python38 part of the above depends on the version and environment (it may be in the form of boost_python-py38).

If you don't know the name of the Boost.Python library to link to, you can look it up with the following command: The ** part of lib **. So that appears is the library name.

Boost.How to find out if you don't know the Python library name


$ ldconfig -p | grep "boost_python3"

Basic usage

From here, we will see how to use each specific function.

Hereafter, assuming that namespace py = boost :: python; is written, it is written as py. Also, global in the code is an object in the global namespace obtained in the code below, as in the first sample.

py::object global = py::import("__main__").attr("__dict__");

py :: eval (): Evaluate an expression in Python and return the result

If you give a Python expression as a string, it will return the result as py :: object type. You can get the result as a C ++ type by combining it with py :: extract <type name> as shown below.

// "2**3"Get the result of
py::object result = py::eval("2**3", global);

//Convert the result to int type and output
std::cout << py::extract<int>(result) << std::endl;

Execution result


8

In the case of this example, the function in Python is not used in particular, so it works even if the namespace global of the second argument is omitted. However, please note that if you omit the second argument, you will not be able to use Python built-in functions such as pow or variables / functions that you have defined separately.

py :: exec (): Pass Python code as a string and execute

As was the case with the first sample, if you give the py :: exec () function the Python code as a string, it will be executed as it is. Unlike py :: eval (), it can also execute multiple commands and define classes, separated by newlines.

py::exec(
    "print('Hello!')\n"
    "print('World!')", global);

Execution result


Hello!
World!

When a new variable is created, it will be generated on the namespace given in the second argument.

//2 in the result variable in Python's global namespace**Substitute 3
py::exec("result = 2**3", global);

//Convert the result to int type and output
std::cout << py::extract<int>(global["result"]) << std::endl;

Execution result


8

py :: exec_file (): Execute Python code from a file

You can use py :: exec_file () to read the contents of a file and execute it in the same way as py :: exec (). The first argument is the file path to the Python script.

py::exec_file("hello.py", global);

This is useful when you want to prepare the definition of your own class as a Python script file separately from C ++.

py :: object :: attr (): Object field / method reference

Fields (member variables) and methods (member functions) of py :: object can be used by using the ʻattr ()` function.

Example of calling str type join method


// ['hoge','fuga','piyo']Create a list called
py::object list = py::eval("['hoge','fuga','piyo']", global);

// 「','.join(list), And combine the strings in the list separated by commas.
py::object result = py::object(",").attr("join")(list);

//Convert the result to string type and output
std::string resultStr = py::extract<std::string>(result);
std::cout << resultStr << std::endl;

Execution result


hoge,fuga,piyo

py :: import (): Using the Python library

You can use py :: import to import a library in the same way as Python's ʻimport` statement.

py::object np = py::import("numpy");

As an example, let's write the following Python code in C ++ without using py :: exec (). This is a sample to display a graph of y = x ^ 2 with matplotlib.

Python code sample


import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-10, 10, 0.1)
y = x ** 2
plt.plot(x, y)
plt.show()

Boost above.C using Python++Sample written in


py::object np = py::import("numpy");
py::object plt = py::import("matplotlib.pyplot");

py::object x = np.attr("arange")(-10, 10, 0.1);
py::object y = x * x;
plt.attr("plot")(x, y);
plt.attr("show")();

(Since x ** 2 cannot be written as it is on the C ++ side, it is set to x * x instead.)

When executed, the graph will be displayed in matplotlib as shown below. y=x^2のグラフ

reference

Recommended Posts

Execute Python code on C ++ (using Boost.Python)
Execute Python code from C # GUI
Notes on using code formatter in Python
[Unity (C #), Python] Try running Python code in Unity using IronPython
Broadcast on LINE using python
[Treasure Data] [Python] Execute a query on Treasure Data using TD Client
Introducing Python using pyenv on Ubuntu 20.04
C code review tool using pycparser
Notes on using MeCab from Python
Preparing python using vscode on ubuntu
Study on Tokyo Rent Using Python (3-2)
Notes on installing Python using PyEnv
Check python code styles using pep8
Notes on using rstrip with python.
Install Python on CentOS using Pyenv
Study on Tokyo Rent Using Python (3-3)
Install Python on CentOS using pyenv
[VS Code] ~ Tips when using python ~
Call C / C ++ from Python on Mac
Create a C wrapper using Boost.Python
Notes for using OpenCV on Windows10 Python 3.8.3.
Detect "brightness" using python on Raspberry Pi 3!
Write test-driven FizzBuzz code using Python doctest.
Getting Python source code metrics using radon
Install python library on Lambda using [/ tmp]
[C] [python] Read with AquesTalk on Linux
Enumerate duplicate combinations (C ++) → Add Python code
Run servomotor on Raspberry Pi 3 using python
Study on Tokyo Rent Using Python (3-1 of 3)
Run Python code on A2019 Community Edition
Detect temperature using python on Raspberry Pi 3!
Video processing using Python + OpenCV on Mac
[Note] Execute Python code from Excel (xlwings)
Run Python in C ++ on Visual Studio 2017
python setup.py test the code using multiprocess
Build Python3.5 + matplotlib environment on Ubuntu 12 using Anaconda
Python on Windows
Detect slide switches using python on Raspberry Pi 3!
twitter on python3
Notes on installing Python3 and using pip on Windows7
[Python] Let's execute the module regularly using schedule
Try using a QR code on a Raspberry Pi
Run Python YOLOv3 in C ++ on Visual Studio 2017
Install Python 3.8.6 on macOS Big Sur using pyenv
Python: Try using the UI on Pythonista 3 on iPad
Python development on Ubuntu on AWS EC2 (using JupyterLab)
Debug with VS Code using boost python numpy
Start using Python
Detect magnet switches using python on Raspberry Pi 3!
Notes on using dict in python [Competition Pro]
python character code
Periodically execute Python Script on AWS Data Pipeline
Note on encoding when LANG = C in Python
python C ++ notes
Try CIing the pushed python code on GitHub.
python on mac
python, openFrameworks (c ++)
[Node-RED] Execute Python on Anaconda virtual environment from Node-RED [Anaconda] [Python]
[Python] Algorithm-aware code
Sound the buzzer using python on Raspberry Pi 3!
Python on Windbg