1、python扩展模块的组成
在python中,对于一些和系统相关的模块或者对性能要求很高的模块,通常会把这个模块C化。扩展模块中主要包含下面几个部分:
· init函数,函数名为:init+模块名,这个函数负责初始化模块,包括设置模块中的方法、对象和其它相关数据的初始化。这个函数是必须的,在脚本中第一次导入这个模块的时候,会先执行这个方法。
· 定义模块方法描述表,它是一个static类型的PyMethodDef数据结构,用来描述模块中定义的方法。
· C函数定义,这些函数是方法描述表中方法的具体实现。
· 如果模块中定义了类,那么还要定义类方法描述表和对象类型。
2、实现python扩展模块实例
当然,有了上面的组成部分,你还是不知道怎么实现一个模块,下面就用官方的一个例子来演示怎么实现一个python扩展模块,这个扩展模块用来实现在python中执行命令行命令。
// spam.c 1 #include "Python.h" 2 3 static PyObject *SpamError; 4 5 static PyObject * 6 spam_system(PyObject *self, PyObject *args) 7 { 8 const char *command; 9 int sts; 10 11 if (!PyArg_ParseTuple(args, "s", &command)) 12 return NULL; 13 sts = system(command); 14 if (sts < 0) { 15 PyErr_SetString(SpamError, "System command failed"); 16 return NULL; 17 } 18 return PyLong_FromLong(sts); 19 } 20 21 static PyMethodDef SpamMethods[] = { 22 {"system", spam_system, METH_VARARGS, 23 "Execute a shell command."}, 24 {NULL, NULL, 0, NULL} /* Sentinel */ 25 }; 26 27 PyMODINIT_FUNC 28 initspam(void) 29 { 30 PyObject *m; 31 32 m = Py_InitModule("spam", SpamMethods); 33 if (m == NULL) 34 return; 35 36 SpamError = PyErr_NewException("spam.error", NULL, NULL); 37 Py_INCREF(SpamError); 38 PyModule_AddObject(m, "error", SpamError); 39 } |
上面的initspam是模块的初始化函数,函数开始调用了Py_InitModule初始化了一个名为spam的模块,模块的方法描述表是SpamMethods,它描述了模块有个名为system的方法,这个方法的c/c++实现是spam_system函数。从spam_system函数可以看到它就是调用system函数执行从python传过来的命令。有了上面的代码,我们怎样在python中使用了?很简单,先将上面代码编译成动态链接库,然后直接在python中用import语句导入这个模块就可以用了。在Windows下的用vs编译就行,不过在vs建立了dll工程后,需要设置下工程的属性,目的是设置python扩展涉及到的头文件路径和动态库。具体设置如下:先在VC++目录中设置include和lib路径,然后在链接器的附加依赖项中添加python27.lib库。
设置好后直接编译就可以了,将编译生成的dll文件后缀名改成pyd,然后就可以在python中直接用import导入这个模块了。是不是非常的简单!!!!
3、实现python扩展模块中定义类
上面的实现是在模块中定义函数来实现执行命令行命令,我们也可以在模块中定义类,然后用类的方法来执行这个命令。代码如下:
// spam.c 1 #include "Python.h" 2 3 static PyObject *SpamError; 4 5 static PyObject * 6 spam_system(PyObject *self, PyObject *args) 7 { 8 const char *command; 9 int sts; 10 11 if (!PyArg_ParseTuple(args, "s", &command)) 12 return NULL; 13 sts = system(command); 14 if (sts < 0) { 15 PyErr_SetString(SpamError, "System command failed"); 16 return NULL; 17 } 18 return PyLong_FromLong(sts); 19 } 20 21 static PyMethodDef SpamMethods[] = { 22 {"system", spam_system, METH_VARARGS, 23 "Execute a shell command."}, 24 {NULL, NULL, 0, NULL} /* Sentinel */ 25 }; 26 27 PyTypeObject *SpamType = NULL; 28 29 PyMODINIT_FUNC 30 initspam(void) 31 { 32 static PyTypeObject _SpamType = { 33 PyObject_HEAD_INIT(NULL) 34 0, // ob_size 35 "spam.Spam", // tp_name 36 sizeof(PyObject), // tp_basicsize 37 0, // tp_itemsize 38 0, // tp_dealloc 39 0, // tp_print 40 0, // tp_getattr 41 0, // tp_setattr 42 0, // tp_compare 43 0, // tp_repr 44 0, // tp_as_number 45 0, // tp_as_sequence 46 0, // tp_as_mapping 47 0, // tp_hash 48 0, // tp_call 49 0, // tp_str 50 0, // tp_getattro 51 0, // tp_setattro 52 0, // tp_as_buffer 53 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , // tp_flags 54 0, // tp_doc 55 0, // tp_traverse 56 0, // tp_clear 57 0, // tp_richcompare 58 0, // tp_weaklistoffset 59 0, // tp_iter 60 0, // tp_iternext 61 SpamMethods, // tp_methods 62 0, // tp_members 63 0, // tp_getset 64 0, // tp_base 65 0, // tp_dict 66 0, // tp_descr_get 67 0, // tp_descr_set 68 0, // tp_dictoffset 69 0, // tp_init 70 0, // tp_alloc 71 PyType_GenericNew, // tp_new 72 }; 73 74 PyObject *m; 75 76 m = Py_InitModule("spam", NULL); 77 if (m == NULL) 78 return; 79 if (PyType_Ready(&_SpamType) < 0) 80 return; 81 SpamType = &_SpamType; 82 Py_INCREF(SpamType); 83 PyModule_AddObject(m, "Spam", (PyObject*)SpamType); 84 SpamError = PyErr_NewException("spam.error", NULL, NULL); 85 Py_INCREF(SpamError); 86 PyModule_AddObject(m, "error", SpamError); 87 } |