How Python calls the C ++ Program
Preface
Everyone knows that Python has the advantages of high development efficiency and ease of use, while C ++ is highly efficient. The two can complement each other, whether Embedded C ++ code in a Python project, or you may need to call the C ++ module by using Python in the C ++ project to implement peripheral functions, the following describes how to export c ++ code to a Python interface.
Original Ecological Export
The Python interpreter is implemented in C. Therefore, as long as the data structure of C ++ can be understood by Python, it can be directly called theoretically. Test1.cpp is implemented 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 the Python interpreter and test the following:
>>> import test1>>> test1.Add(1,2)3
Pay attention to the following points:
- If the generated dynamic library name is test1, The inittest1 function must exist in the source file, 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 data to the database. C and C ++ have different encoding methods for function symbols, when coding function symbols, C ++ considers the function length and parameter type.
nm test1.soView the function symbol. The c ++ filt tool can use the symbol to reverse calculate the function prototype.
Implemented through boost
We use the same example 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 BOOST_PYTHON_MODULE parameter is the name of the module 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:During compilation, you must specify the path of the boost header file and Library. Here are/usr/local/include and/usr/local/lib respectively.
Or use setup. py to export the module.
#!/usr/bin/env pythonfrom distutils.core import setupfrom distutils.extension import Extensionsetup(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.
Run the following command:
python setup.py build
In this case, the build directory is generated, test2.so in the directory is found, and the directory at the same level is entered. The verification is as follows:
>>> import test2>>> test2.Add(1,2)3>>> test2.Del(1,2)-1
Export class
Test3.cpp implementation:
#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:The. def usage in BOOST_PYTHON_MODULE is a bit similar to the Python syntax, equivalent
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_python
The test is as follows:
>>> import test3>>> test = test3.Test()>>> test.Add(1,2)3>>> test.Del(1,2)-1
Export variable parameters
Test4.cpp implementation:
#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"));}
Here, the Add and Del functions both use the default parameters. Del is a common function, and Add is a class member function. Different macros are called here, the last two parameters of the macro represent the minimum number of parameters and the maximum number of parameters of the function.
The 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_python
The 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 interfaces with Python objects
Since it is exported as a Python interface, the caller will inevitably use the Python-specific data structure, such as tuple, list, And dict. Because the original ecological method is too troublesome, only the boost usage method is recorded here, suppose you want to implement the following Python Functions
def Square(list_a){ return [x * x for x in list_a]}
Calculate the square of each element in the input list and return the list result.
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 implementsboost::python::tuple,boost::python::list,boost::python::dictThe usage of these data types is basically the same as that of Python. For more information, see boost/python/tuple. hpp In the boost header file and other corresponding files.
Another commonly used function isboost::python::make_tuple()The usage is as follows:
boost::python::tuple(int a, int b, int c){ return boost::python::make_tuple(a, b, c);}
Summary
The above is all about this article. I hope this article will help you in your study or work. If you have any questions, please leave a message.