Search This Blog

Labels

Friday, December 17, 2010

《扩展和嵌入Python解释器(译稿)》1.4 The Module’s Method Table and Initialization Function

1.4 The Module’s Method Table and Initialization Function

模块的方法表和初始化函数

I promised to show how spam_system() is called from Python programs. First, we need to list its name and address in a “method table”:

我将展示在Python程序中是怎样调用spam_system()的。首先,我们需要将它的名字和地址列入一个“方法列表”:

static PyMethodDef SpamMethods[] = {

{

    "system", spam_system, METH_VARARGS,

    "Execute a shell command."},

    …

    {NULL, NULL, 0, NULL} /* Sentinel */

};

Note the third entry (‘METH_VARARGS’). This is a flag telling the interpreter the calling convention to be used for the C function. It should normally always be ‘METH_VARARGS’ or ‘METH_VARARGS | METH_KEYWORDS’; a value of 0 means that an obsolete variant of PyArg_ParseTuple() is used.

注意第三个条目(‘METH_VARARGS’),这是一个标识用来告诉解释器调用要转化以用于C函数。正常地应该总是‘METH_VARARGS’或‘METH_VARARGS | METH_KEYWORDS‘;为0的话则表示使用的是PyArg_ParseTuple()的一个已被废弃的变体

When using only ‘METH_VARARGS’, the function should expect the Python-level parameters to be passed in as a tuple acceptable for parsing via PyArg_ParseTuple(); more information on this function is provided below.

当仅使用‘METH_VARARGS’标识时,Python层的参数应该以一个由PyArg_ParseTuple()解析时可接受的元组的方式传入。

The METH_KEYWORDS bit may be set in the third field if keyword arguments should be passed to the function. In this case, the C function should accept a third ‘PyObject *’ parameter which will be a dictionary of keywords. Use PyArg_ParseTupleAndKeywords() to parse the arguments to such a function.

METH_KEYWORDS位可设置在方法列表的第三域,如果关键值参数要传给函数的话。这种情况下,C函数应当接受一个类型为‘PyObject*’的参数,该参数是一个关键值的字典。使用PyArg_ParseTupleAndKeywords()来为这样的函数解析参数。

The method table must be passed to the interpreter in the module’s initialization function. The initialization function must be named initname(), where name is the name of the module, and should be the only non- static item defined in the module file:

方法列表在模块的初始化函数中传给解释器。初始化函数必须命名为:initname()这里的name是模块的名字,并且应当为模块文件中定义的唯一非静态项。

PyMODINIT_FUNC

initspam(void)

{

    (void) Py_InitModule("spam", SpamMethods);

}

Note that PyMODINIT_FUNC declares the function as void return type, declares any special linkage declarations required by the platform, and for C++ declares the function as extern "C".

注意到PyMODINIT_FUNC声明初始化函数为void返回类型、声明平台相关的特殊链接声明,对于C++中,可以将函数声明为extern "C"。

When the Python program imports module spamfor the first time, initspam()is called. (See below for comments about embedding Python.) It calls Py_InitModule(), which creates a “module object” (which is inserted in the dictionary sys.modulesunder the key "spam"), and inserts built-in function objects into the newly created module based upon the table (an array ofPyMethodDefstructures) that was passed as its second argument. Py_InitModule()returns a pointer to the module object that it creates (which is unused here). It aborts with a fatal error if the module could not be initialized satisfactorily, so the caller doesn’t need to check for errors.

当Python程序第一次导入spam模块时,initspam()被调用。(参见下方对Python嵌入的注释)initspam()调用Py_InitModule(),Py_InitModule()创建一个“模块对象”(添加到了sys.modules字典的"spam"关键值下),并基于方法列表(一个PyMethodDef结构体的数组),将内建函数对象添加到新创建的模块对象。

When embedding Python, the initspam()function is not called automatically unless there’s an entry in the _PyImport_Inittab table. The easiest way to handle this is to statically initialize your statically-linked modules by directly calling initspam() after the call to Py_Initialize():

当嵌入Python时,initspam()函数不会被自动调用,除非在_PyImport_Inittab 列表中有一个条目。处理这个问题的最简方法是在调用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();

}

An example may be found in the file ‘Demo/embed/demo.c’ in the Python source distribution.

在源码发布版的目录Demo/embed/demo.c下可以找到一个例子。

Note: Removing entries from sys.modulesor importing compiled modules into multiple interpreters within a process (or following a fork()without an intervening exec()) can create problems for some extension modules. Extension module authors should exercise caution when initializing internal data structures. Note also that the reload()function can be used with extension modules, and will call the module initialization function (initspam() in the example), but will not load the module again if it was loaded from a dynamically loadable object file (‘.so’ on UNIX, ‘.dll’ on Windows).

注意:对于有些扩展模块,从sys.modules中移除条目或将已编译了的模块导入一个进程中的多个解释器(或在fork()之后没有exec()),会引发问题。扩展模块的作者在初始化内部数据结构时应当使用提醒。同样注意reload()函数也能用于扩展模块,并且会调用模块的初始化函数(例子中的initspam()),但如果模块是从可动态载入的目标文件(UNIX下的‘.so’文件,Windows下的‘.dll’文件)中载入时,模块不会再次载入。

A more substantial example module is included in the Python source distribution as ‘‘Modules/xxmodule.c’. This file may be used as a template or simply read as an example. Themodulator.pyscript included in the source distribution or Windows install provides a simple graphical user interface for declaring the functions and objects which a module should implement, and can generate a template which can be filled in. The script lives in the ‘Tools/modulator/’ directory; see the ‘README’ file there for more information.

一个更的切实的例子包含在Python源码的‘‘Modules/xxmodule.c’目录下。这个文件可以作为一个模板使用或者仅仅作一个例子阅读。modulator.py 脚本包含进了源码版而Windows下的安装文件提供了一个简单的图形化界面,以声明模块要实现的函数和对象,并生成一个可被填充的模板。脚本位于‘Tools/modulator/’目录下,更多信息可参见目录下的‘README’文件。

No comments:

Post a Comment