前面我们用swig封装了c++的代码给java使用:
如何用SWIG封装c++接口给java使用?-CSDN博客
但是由于我们的代码写的太好了,python用户也想用,我们需要将c++代码封装一下给python用户使用。
这种需求很常见吧。
现在AI动不动就是用python进行训练,但是有些需要提高运行速度的时候还是需要用C/C++进行编写。
python与c++进行交互的方式好像挺多的。
ctype,pybind11,但这里我们还是使用swig。
代码还是使用我们在java那里的例子。
让我们看看我们优秀的代码是怎么给python程序员带来震撼的。
apple.h
#ifndef __APPLE_H__
#define __APPLE_H__enum class LogLevel {Trace /// Most detailed output,Debug,Info,Warn,Error,Fatal /// Least detailed output,Current /// no-op, value indicates current level should be retained
};class Apple
{
public:Apple();int GetColor(void);void SetColor(int color);private:int m_nColor;
};
#endif
apple.cpp
#include "apple.h"Apple::Apple() : m_nColor(0)
{
}void Apple::SetColor(int color)
{m_nColor = color;
}int Apple::GetColor(void)
{return m_nColor;
}
我们在这两个文件里面定义了一个类Apple,给它添加了两个成员函数Setcolor和GetColor,是不是非常合理,一般的C++都是这么写的。
写swig接口文件 apple.i
%module demo
%{
/* Includes the header in the wrapper code */
#include "apple.h"
%}/* Parse the header file to generate wrappers */
%include "apple.h"
用swig生成中间代码
swig -python -c++ apple.i
生成了 demo.py和 apple_wrap.cxx 两个文件
编译一下这个 cxx文件,生成 _demo.so
g++ -g -c apple.cpp -o apple.o
g++ -fpic -shared apple_wrap.cxx -o _demo.so -I/usr/include/python3.8 apple.o
用python调用一下试试。
main.py
import demo;a = demo.Apple();
a.SetColor(2);
print(a.GetColor());
运行之
pp@dell:~/wrapper$ python3 main.py
2
非常好!
我们来看一下swig给我们生成的中间文件都有什么内容。
apple_wrap.cxx 的内容:
文件总共3804行,我们只看比较核心的部分,函数的实现。
SWIGINTERN PyObject *_wrap_Apple_SetColor(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {PyObject *resultobj = 0;Apple *arg1 = (Apple *) 0 ;int arg2 ;void *argp1 = 0 ;int res1 = 0 ;int val2 ;int ecode2 = 0 ;PyObject *swig_obj[2] ;if (!SWIG_Python_UnpackTuple(args, "Apple_SetColor", 2, 2, swig_obj)) SWIG_fail;res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Apple, 0 | 0 );if (!SWIG_IsOK(res1)) {SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Apple_SetColor" "', argument " "1"" of type '" "Apple *""'"); }arg1 = reinterpret_cast< Apple * >(argp1);ecode2 = SWIG_AsVal_int(swig_obj[1], &val2);if (!SWIG_IsOK(ecode2)) {SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Apple_SetColor" "', argument " "2"" of type '" "int""'");} arg2 = static_cast< int >(val2);(arg1)->SetColor(arg2);resultobj = SWIG_Py_Void();return resultobj;
fail:return NULL;
}SWIGINTERN PyObject *Apple_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {PyObject *obj;if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;SWIG_TypeNewClientData(SWIGTYPE_p_Apple, SWIG_NewClientData(obj));return SWIG_Py_Void();
}SWIGINTERN PyObject *Apple_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {return SWIG_Python_InitShadowInstance(args);
}static PyMethodDef SwigMethods[] = {{ "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL},{ "new_Apple", _wrap_new_Apple, METH_NOARGS, NULL},{ "Apple_GetColor", _wrap_Apple_GetColor, METH_O, NULL},{ "Apple_SetColor", _wrap_Apple_SetColor, METH_VARARGS, NULL},{ "delete_Apple", _wrap_delete_Apple, METH_O, NULL},{ "Apple_swigregister", Apple_swigregister, METH_O, NULL},{ "Apple_swiginit", Apple_swiginit, METH_VARARGS, NULL},{ NULL, NULL, 0, NULL }
};static PyMethodDef SwigMethods_proxydocs[] = {{ NULL, NULL, 0, NULL }
};
demo.py的内容就比较简单了,只有90行
基本上 就是一个封装和函数调用转发。
# This file was automatically generated by SWIG (http://www.swig.org).
# Version 4.0.1
#
# Do not make changes to this file unless you know what you are doing--modify
# the SWIG interface file instead.from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (2, 7, 0):raise RuntimeError("Python 2.7 or later required")# Import the low-level C/C++ module
if __package__ or "." in __name__:from . import _demo
else:import _demotry:import builtins as __builtin__
except ImportError:import __builtin__def _swig_repr(self):try:strthis = "proxy of " + self.this.__repr__()except __builtin__.Exception:strthis = ""return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)def _swig_setattr_nondynamic_instance_variable(set):def set_instance_attr(self, name, value):if name == "thisown":self.this.own(value)elif name == "this":set(self, name, value)elif hasattr(self, name) and isinstance(getattr(type(self), name), property):set(self, name, value)else:raise AttributeError("You cannot add instance attributes to %s" % self)return set_instance_attrdef _swig_setattr_nondynamic_class_variable(set):def set_class_attr(cls, name, value):if hasattr(cls, name) and not isinstance(getattr(cls, name), property):set(cls, name, value)else:raise AttributeError("You cannot add class attributes to %s" % cls)return set_class_attrdef _swig_add_metaclass(metaclass):"""Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""def wrapper(cls):return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())return wrapperclass _SwigNonDynamicMeta(type):"""Meta class to enforce nondynamic attributes (no new attributes) for a class"""__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)LogLevel_Trace = _demo.LogLevel_Trace
LogLevel_Debug = _demo.LogLevel_Debug
LogLevel_Info = _demo.LogLevel_Info
LogLevel_Warn = _demo.LogLevel_Warn
LogLevel_Error = _demo.LogLevel_Error
LogLevel_Fatal = _demo.LogLevel_Fatal
LogLevel_Current = _demo.LogLevel_Current
class Apple(object):thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")__repr__ = _swig_reprdef __init__(self):_demo.Apple_swiginit(self, _demo.new_Apple())def GetColor(self):return _demo.Apple_GetColor(self)def SetColor(self, color):return _demo.Apple_SetColor(self, color)__swig_destroy__ = _demo.delete_Apple# Register Apple in _demo:
_demo.Apple_swigregister(Apple)
可以说,速度是非常的快。完全不用手动写多余的代码。
调用也非常简单,推荐使用SWIG。