使用C++擴展Python的時候主要實現:
* 將C++中的函數引入到Python中去
* 以及將C++中的類引入到Python中去
同時還涉及到:
* 返回值擴展類型
* 參數檢測
* 異常處理
* 軟件程序編譯以及發佈
大部分是模式化編程,套模本即可。
#ifndef _DM_PYX_ACTION_HPP
#define _DM_PYX_ACTION_HPP
#include <Python.h>
#include <dm/scada/scada.hpp>
namespace dm{
namespace pyx{
struct SAction{
PyObject_HEAD
int idx;
const dm::scada::SActionInfo* pInfo;
};
extern PyTypeObject* TypeAction;
int init_action( PyObject* module );
};
};
#endif
定義了一個擴展類的頭文件。
因爲需要在其他擴展中使用該擴展類,作爲數據返回,或者作爲參數引用。
這裏使用的是C++的命名空間寫法。
實現的部分,基本上就是套模本了。
#include "action.hpp"
#include <dm/scada/actionmgr.hpp>
#include <dm/scada/actiondescmgr.hpp>
#include <dm/os/log/logger.hpp>
static const char* logModule = "action.pyx.dm";
namespace dm{
namespace pyx{
typedef SAction LObject;
static void l_dealloc( LObject* self,PyObject* args ){
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject* l_new( PyTypeObject *type, PyObject *args, PyObject *kwds ){
return type->tp_alloc(type,0);
}
static PyObject * l_repr(LObject * self){
const dm::scada::SActionInfo* pInfo = self->pInfo;
return PyString_FromFormat("Action:{idx:%d,id:%d,name:%s,desc:%s,invOff:%d,off:%d,on:%d,invOn:%d,level:%d,save:%d,report:%d}",
self->idx,
self->pInfo->id,self->pInfo->name.c_str(),self->pInfo->desc.c_str(),
self->pInfo->desc_invOff,self->pInfo->desc_off,self->pInfo->desc_on,self->pInfo->desc_invOn,
self->pInfo->level,self->pInfo->isFlagSave(),self->pInfo->isFlagReportTimed());
}
static int l_init(LObject *self, PyObject *args, PyObject *kwds)
{
// 傳遞的參數是索引號
if (!_PyArg_NoKeywords("Action()", kwds)){
log().error(STATICMODULE "構造函數錯誤");
return -1;
}
PyArg_ParseTuple(args,"i",&(self->idx));
if( self->idx<0 || self->idx>dm::scada::CActionMgr::ins().size() ){
log().warnning(STATICMODULE "索引(%d)溢出[0,%d]",self->idx,dm::scada::CActionMgr::ins().size());
return -1;
}
self->pInfo = dm::scada::CActionMgr::ins().info(self->idx);
return 0;
}
static PyObject* l_id( LObject* self ){
return PyInt_FromLong(self->pInfo->id);
}
static PyObject* l_name( LObject* self ){
return PyString_FromString(self->pInfo->name.c_str());
}
static PyObject* l_desc( LObject* self ){
return PyString_FromString(self->pInfo->desc.c_str());
}
static PyObject* l_invOff( LObject* self ){
return PyInt_FromLong(self->pInfo->desc_invOff);
}
static PyObject* l_off( LObject* self ){
return PyInt_FromLong(self->pInfo->desc_off);
}
static PyObject* l_on( LObject* self ){
return PyInt_FromLong(self->pInfo->desc_on);
}
static PyObject* l_invOn( LObject* self ){
return PyInt_FromLong(self->pInfo->desc_invOn);
}
static PyObject* l_level( LObject* self ){
return PyInt_FromLong(self->pInfo->level);
}
static PyObject* l_flagSave( LObject* self ){
return PyInt_FromLong(self->pInfo->isFlagSave());
}
static PyObject* l_flagReport( LObject* self ){
return PyInt_FromLong(self->pInfo->isFlagReportTimed());
}
static PyTypeObject lTypeObject = {
PyVarObject_HEAD_INIT(NULL,0)
};
PyTypeObject* TypeAction = &lTypeObject;
static PyMethodDef lMethodDef[] = {
{"id",(PyCFunction)l_id,METH_NOARGS,"獲取動作ID"},
{"name",(PyCFunction)l_name,METH_NOARGS,"獲取動作名稱"},
{"desc",(PyCFunction)l_desc,METH_NOARGS,"獲取動作描述"},
{"invOff",(PyCFunction)l_invOff,METH_NOARGS,"獲取無效分描述索引號"},
{"off",(PyCFunction)l_off,METH_NOARGS,"獲取分描述索引號"},
{"on",(PyCFunction)l_on,METH_NOARGS,"獲取合描述索引號"},
{"invOn",(PyCFunction)l_invOn,METH_NOARGS,"獲取無效合描述索引號"},
{"level",(PyCFunction)l_level,METH_NOARGS,"獲取級別"},
{"flagSave",(PyCFunction)l_flagSave,METH_NOARGS,"獲取標誌:是否存盤"},
{"flagReport",(PyCFunction)l_flagReport,METH_NOARGS,"獲取標誌:是否上報"},
{NULL}
};
int init_action( PyObject* module ){
lTypeObject.tp_dealloc = (destructor)l_dealloc;
lTypeObject.tp_new = l_new;
lTypeObject.tp_init = (initproc)l_init;
lTypeObject.tp_repr = (reprfunc)l_repr;
lTypeObject.tp_name = "Action";
lTypeObject.tp_doc = "動作信息類";
lTypeObject.tp_basicsize = sizeof(LObject);
lTypeObject.tp_itemsize = 0;
lTypeObject.tp_flags = Py_TPFLAGS_DEFAULT;
lTypeObject.tp_methods = lMethodDef;
if( PyType_Ready(&lTypeObject)<0 )
return 0;
Py_INCREF(&lTypeObject);
PyModule_AddObject(module,"Action",(PyObject*)&lTypeObject);
return 1;
}
}
}
這裏的模版實現時,類型和對象都使用了別名,LObject, l_dealloc,等。方便類的模板套用,而不用改那麼多的類型名和函數名。
關於PyObject的返回的處理的考量,參數錯誤的時候,我做的是使用return NULL。對於正常查詢失敗的返回None對象。