Home  >  Article  >  Backend Development  >  Detailed explanation of how Python calls C++ programs

Detailed explanation of how Python calls C++ programs

高洛峰
高洛峰Original
2017-02-20 10:28:281453browse

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

  1. 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

  2. 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.soView 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_python

Test As follows

>>> import test3
>>> test = test3.Test()
>>> test.Add(1,2)
3
>>> test.Del(1,2)
-1

Export variable parameter function

test4.cpp is implemented as follows

#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 respectively

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 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

boost::python::make_tuple( )

, 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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn