python扩展:包装C++类

转载注明出处:http://blog.csdn.net/you_lan_hai/article/details/8597451

// TestPython.cpp : 定义控制台应用程序的入口点。
// author: 游蓝海
// blog: http://blog.csdn.net/you_lan_hai

#include "stdafx.h"

#include <iostream>
using namespace std;

#include "../python/Include/Python.h"
#include "../python/Include/structmember.h"

//有多个参数的python导出函数
static PyObject* py_test(PyObject* self, PyObject * args)
{
        cout<<"this message comes from C++"<<endl;

        Py_IncRef(Py_None);
        return Py_None;
}

//方法定义
static PyMethodDef lazyMethods[] =
{
        {"test", PyCFunction(py_test), METH_VARARGS, "just for test"},
        {NULL, NULL, NULL, NULL}, //结束标志
};

//python导出类
class TestPyClass : public PyObject
{
public:
        TestPyClass(PyTypeObject * pType)
                : id_(0)
                , score_(99)
        {
                if(PyType_Ready(pType) < 0)  
                {
                        cout<<"PyType_Ready faild."<<endl;
                } 
                PyObject_INIT(this, pType);
        }
        virtual ~TestPyClass()
        {

        }

        static PyObject* py_new(PyTypeObject * pType, PyObject *, PyObject *)
        {
                return new TestPyClass(pType);
        }

        static void py_dealloc(PyObject * self)
        {
                delete (TestPyClass*)self;
        }

        //init方法。
        static int py_init(PyObject * self, PyObject * args, PyObject *)
        {
                TestPyClass* pThis = (TestPyClass*)self;
                if(!PyArg_ParseTuple(args, "ii", &pThis->id_, &pThis->score_))
                {
                        return 0;
                }
                return 1;
        }

        PyObject* py_test(PyObject * args)
        {
                cout<<"this message comes from TestPyClass."<<endl;

                Py_IncRef(Py_None);
                return Py_None;
        }

        //导出函数
        static PyObject* _py_test(PyObject* self, PyObject * args)
        {
                return ((TestPyClass*)self)->py_test(args);
        }

        int id_;
        int score_;
};

/*如果类中有虚函数,则类对象开始地址为一个虚函数表的地址。
由于PyObject没有虚函数,而子类有虚函数,则子类与基类不共起始地址。
*/
#define offsetofVirtual(type, member) ( (int) & ((type*)0) -> member - sizeof(void*))

//成员变量
static PyMemberDef TestClassMembers[] =
{
        {"id", T_INT, offsetofVirtual(TestPyClass, id_), 0, "id"},
        {"score", T_INT, offsetofVirtual(TestPyClass, score_), 0, "score"},
        {NULL, NULL, NULL, 0, NULL},
};

//成员函数
static PyMethodDef TestClassMethods[] =
{
        {"test", PyCFunction(TestPyClass::_py_test), METH_VARARGS, "just for test"},
        {NULL, NULL, NULL, NULL},
};

//类类型
static PyTypeObject TestPyClass_Type = {
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "TestPyClass",
        sizeof(TestPyClass),
        0,
        (destructor)TestPyClass::py_dealloc,            /* tp_dealloc */
        0,                                                                                      /* tp_print */
        0,                                          /* tp_getattr */
        0,                                          /* tp_setattr */
        0,                                          /* tp_compare */
        0,                                                                                      /* tp_repr */
        0,                                          /* tp_as_number */
        0,                                                                                      /* tp_as_sequence */
        0,                                                                                      /* tp_as_mapping */
        0,                                                                                      /* tp_hash */
        0,                                          /* tp_call */
        0,                                          /* tp_str */
        0,                                                                                      /* tp_getattro */
        0,                                          /* tp_setattro */
        0,                                          /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,      /* tp_flags */
        0,                                                                                      /* tp_doc */
        0,                                                                                      /* tp_traverse */
        0,                                                                                      /* tp_clear */
        0,                                                                                      /* tp_richcompare */
        0,                                          /* tp_weaklistoffset */
        0,                                                                                      /* tp_iter */
        0,                                          /* tp_iternext */
        TestClassMethods,                           /* tp_methods */
        TestClassMembers,                           /* tp_members */
        0,                                          /* tp_getset */
        0,                                          /* tp_base */
        0,                                          /* tp_dict */
        0,                                          /* tp_descr_get */
        0,                                          /* tp_descr_set */
        0,                                          /* tp_dictoffset */
        (initproc)TestPyClass::py_init,             /* tp_init */
        0,                                                                                      /* tp_alloc */
        (newfunc)TestPyClass::py_new,               /* tp_new */
        0,                                                                                      /* tp_free */
};

void initLazy(void)
{
        PyObject* pModule = Py_InitModule("Lazy", lazyMethods);

        if (pModule)
        {
                Py_IncRef((PyObject*)&TestPyClass_Type);

                PyModule_AddObject(pModule, "TestClass", (PyObject*)&TestPyClass_Type);
        }
}

int _tmain(int argc, _TCHAR* argv[])
{
        Py_SetPythonHome("F:/workspace/test/python");
        Py_Initialize();
        if (!Py_IsInitialized())
        {
                cout<<"Py_Initialize faild! "<<endl;
                PyErr_Print();
                return 0;
        }

        cout<<"Python initialize success."<<endl;
        initLazy();
        PyRun_SimpleString("import Lazy");
        PyRun_SimpleString("Lazy.test()");
        PyRun_SimpleString("a = Lazy.TestClass(2, 3)");
        PyRun_SimpleString("print dir(a)");
        PyRun_SimpleString("a.test()");
        PyRun_SimpleString("print 'a.id = ', a.id, ', a.score = ', a.score");

#if 0
        //测试对象大小。含虚函数的类,会大4个字节。
        
        cout<<"sizeof(PyObject)"<<sizeof(PyObject)<<endl;
        cout<<"sizeof(TestPyClass)"<<sizeof(TestPyClass)<<endl;

        TestPyClass testPy(&TestPyClass_Type);
        cout<<"testPy addr:"<<&testPy<<" "<<(PyObject*)&testPy
                <<", id:"<<&(((TestPyClass*)0)->id_)<<endl;
#endif

        Py_Finalize();
        return 0;
}