使用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对象。