下面,我演示如何从Python程序调用spam_system().首先,我们需要在’方法表’列出名称和地址:
static PyMethodDef SpamMethods[] = { ... {"system", spam_system, METH_VARARGS, "Execute a shell command."}, ... {NULL, NULL, 0, NULL} /* Sentinel */ };
注意第三项("METH_VARARGS")。这是一个标志,用来告诉解释器应使用调用C函数的规则。它一般总是 "METH_VARARGS" 或 "METH_VARARGS | METH_KEYWORDS"; 值0表示PyArg_ParseTuple()函数使用的变量是废弃的。
当仅使用时"METH_VARARGS",函数希望Python-level参数经由PyArg_ParseTuple()被传递进来。下面提供这个函数的详细信息。
如果关键字参数被传递到函数,第三个字段的METH_KEYWORDS应被设置为1。在这中情况下, C函数应接受第三个 "PyObject *"参数,此参数是关键字字典。使用PyArg_ParseTupleAndKeywords()函数分析参数。方法表必须在模块初始化函数中传递到解释器。初始化函数必须命名为initname(), 名称是模块名称,并且在模块文件的定义是non-static的。
PyMODINIT_FUNC initspam(void) { (void) Py_InitModule("spam", SpamMethods); }
注意: PyMODINIT_FUNC声明函数返回值类型为void,并声明平台所需的特定连接指示,对于C++声明函数为extern "C"类型。
当Python程序第一次导入spam模块时,initspam()函数被调用 (参见下面关于嵌入Python的说明)。 initspam()函数调用Py_InitModule(),Py_InitModule()函数创建模块对象 (插入到sys.modules
字典
"spam"
键下),并在根据第二个传入参数的表(PyMethodDef结构数组)所创建的对象的基础上,插入内置功能对象。 Py_InitModule()函数返回一个指向它所创建对象的指针(此处没有使用)。如果模块不能正确初始化,函数则因严重错误终止,所以,调用者不必检查错误。
当嵌入Python时,除非在_PyImport_Inittab表中有一项,否则initspam()不被自动调用。最早的处理此事的办法是:在调用Py_Initialize()后,直接调用你的静态初始化的静态连接模块的initspam()
int main(int argc, char *argv[]) { /* Pass argv[0] to the Python interpreter */ Py_SetProgramName(argv[0]); /* Initialize the Python interpreter. Required. */ Py_Initialize(); /* Add a static module */ initspam(); }
在Python源代码包,你能找到一个例子:Demo/embed/demo.c。
注意: 对于一些扩展模块,从sys.modules
模块删除入口点,或在一个进程(或在没有exec()干预的fork()后)中的多个解释器中导入编译后的模块,会产生一些问题。当初始化内部数据结构时,模块作者应该小心处理。还要注意扩展模块能够使用reload()函数,并且调用模块的初始化函数(在本例中是initspam()函数),但如果模块是从可动态加载文件(.so on Unix, .dll on Windows)中加载的,则不会再次加载模块。
Python源代码发布包中包括更多模块例子,一般在Modules/xxmodule.c。这些文件可以用做模板或简单阅读的例子。源代码发布中包括modulator.py脚本或windows安装提供一个简单的图形界面接口声明函数和要实现的模块对象,并产生一个可以填充的模板。脚本位于Tools/modulator/路径,详细信息请参阅README文件。