Home > Article > Backend Development > Detailed explanation of how Python calls C++ programs
Preface
Everyone knows that the advantages of Python are high development efficiency and ease of use, while C++ has high operating efficiency. The two can complement each other, whether in Python If you embed C++ code in a project, or use Python to implement peripheral functions in a C++ project, you may encounter the need for Python to call C++ modules. Here are several basic methods for exporting C++ code into Python interfaces. Let’s learn together. .
Original export
The Python interpreter is implemented in C, so as long as our C++ data structure can be understood by Python , in theory, it can be called directly. We implement test1.cpp as follows
#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); }
The compilation command is as follows
g++ -fPIC -shared test1.cpp -I/usr/include/python2.6 -o test1.so
Run Python interpretation The test is as follows
>>> import test1 >>> test1.Add(1,2) 3
There are a few points to note here
If the name of the generated dynamic library is test1, the source file must have the inittest1 function, and the first parameter of Py_InitModule must be "test1", otherwise the Python import module will fail
If it is a cpp source file, the inittest1 function must be modified with extern "C". If it is a c source file, it is not required. The reason is that the Python interpreter will look for functions such as initxxx when importing libraries, and C and C++ encode function symbols differently. C++ will consider the function length and parameter type when encoding function symbols. Specifically, you can use nm test1.so
View function symbols, the c++filt tool can decode the function prototype through symbols
Achieved through boost
We use the same example as above to implement test2.cpp as follows
#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); }
The parameters of BOOST_PYTHON_MODULE are The module name to be exported
The compilation command is as follows
g++ test2.cpp -fPIC -shared -o test2.so -I/usr/include/python2.6 -I/usr/local/include -L/usr/local/lib -lboost_python
Note: is required during compilation Specify the paths to the boost header files and libraries, here they are /usr/local/include and /usr/local/lib
or export the module through 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"]) ])
The first parameter of Extension is the module name, and the second parameter is the file name
Execute the following command
python setup.py build
The build directory will be generated at this time, find test2.so inside, and enter the same level directory, verify as follows
>>> import test2 >>> test2.Add(1,2) 3 >>> test2.Del(1,2) -1
Export class
test3.cpp is implemented as follows
#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); }
##Note: How to use .def in BOOST_PYTHON_MODULE Somewhat similar to Python's syntax, it is equivalent to
class_<Test>("Test").def("Add", &Test::Add); class_<Test>("Test").def("Del", &Test::Del);The compilation command is as follows
g++ test3.cpp -fPIC -shared -o test3.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_pythonTest As follows
>>> import test3 >>> test = test3.Test() >>> test.Add(1,2) 3 >>> test.Del(1,2) -1
Export variable parameter function
#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")); }Both the Add and Del functions here use default parameters. Del is an ordinary function and Add is a class member function. Different macros are called here. Macros The last two parameters represent the minimum number of parameters and the maximum number of parameters of the function respectivelyThe compilation command is as follows
g++ test4.cpp -fPIC -shared -o test4.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_pythonThe test is as follows
>>> 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
##Export an interface with Python objects
Since it is exported as a Python interface , the caller will inevitably use Python-specific data structures, such as tuple, list, dict. Since the original ecological method is too troublesome, only the usage of boost is recorded here. Assume that the following Python function functions are to be implemented
def Square(list_a) { return [x * x for x in list_a] }
That is, calculate the square of each element of the incoming list and return the result of list type
The code is as follows
#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); }
The compilation command is as follows
g++ test5.cpp -fPIC -shared -o test5.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python
The test is as follows
>>> import test5 >>> test5.Square([1,2,3]) [1, 4, 9]
boost implementation Here are the data types of
boost::python::tuple, boost::python::list
, boost::python::dict
, how to use them It is basically consistent with Python. For specific methods, you can view boost/python/tuple.hpp and other corresponding files in the boost header file. Another commonly used function is
, the usage method is as follows
boost::python::tuple(int a, int b, int c) { return boost::python::make_tuple(a, b, c); }
For more detailed explanations on how Python calls C++ programs, please pay attention to the PHP Chinese website for related articles!