我刚刚开始使用Python C扩展,并且很好奇为什么可以从Python调用的C函数必须使用2个PyObject *参数并返回PyObject *。我写了以下“Hello World”扩展名:
#include <Python.h>
static PyObject *
hello_world(PyObject *self, PyObject *noargs)
{
printf("Hello World\n");
return Py_BuildValue("");
}
// Module functions table.
static PyMethodDef
module_functions[] = {
{ "hello_world", hello_world, METH_NOARGS, "hello world method" },
{ NULL }
};
// This function is called to initialize the module.
PyMODINIT_FUNC
inittesty2(void)
{
Py_InitModule("testy2", module_functions);
}
为什么我(特别是使用METH_NOARGS)不能使用以下hello_world方法:
static void
hello_world()
{
printf("Hello World\n");
}
答案 0 :(得分:10)
关于各种PyObject
指针,有几点要说。
返回类型所需的那个用于异常处理机制。具体来说,如果你的函数返回一个空指针,Python解释器将抛出一个例外。 (只有在调用其中一个PyErr_..
函数来设置特定异常后才应该这样做。)
这也意味着每当你不想抛出异常时,必须返回一个指向真实PyObject
的指针。如果没有特别的东西你的函数应该返回,只需返回Py_None
(最好使用Py_RETURN_NONE
宏来使引用计数正确)或“true”(使用Py_RETURN_TRUE
)。
第一个参数,PyObject *self
指向调用函数的对象,或指向它所属的模块实例。请注意,您定义的每个函数都是类方法或模块方法。没有完全独立的函数。
第二个参数,PyObject *args
指向函数参数(可以是元组或多个参数的列表)。你是正确的指出一个不带任何参数的函数不应该需要这个 - 而且,据我所知,你是对的。你不必定义它;你可以简单地将函数定义为
static PyObject *PyMyClass_MyFunc(PyObject *self) {
/* ..do something.. */
Py_RETURN_TRUE;
}
当你将{strong}加入到你定义的数据类型的PyCFunction
时,你仍然需要强制转换为PyMethodDef
,但我相信强制转换是安全的当你使用METH_NOARGS
标志时。 但请注意以下评论可能存在的风险。
最后,一个函数实际上可能有一个第三个参数,如下所示:
static PyObject *PyMyClass_Func(PyObject *self, PyObject *args, PyObject *kwds)
{
/*...*/
}
第三个参数用于命名的,可选的参数。在这种情况下,您也必须将函数指针强制转换为PyCFunction
,但如果您为函数设置了正确的标志(METH_KEYWORDS
),这也是安全的。方法表。
答案 1 :(得分:4)
模块级函数的第一个参数是模块对象。在C中定义类时(相同的PyMethodDef
结构用于那里的方法),第一个参数是实例(类似于Python中的self
)。
使用METH_NOARGS
时,Python会将NULL
作为第二个参数传递。他们可以使用一个参数将其转换为函数,但我猜他们认为不需要它。
返回值很容易解释。每个Python函数都有一个返回值。如果您未在Python中明确使用return
,则该函数将返回None
。
当然在C语言中你必须明确返回值,所以如果你不使用它,你必须自己返回None
。 Python为此提供了一个宏:
Py_RETURN_NONE;
或者,您可以自己访问全局None
实例:
Py_INCREF(Py_None);
return Py_None;
但宏更容易使用。
您可以认为返回NULL
应该等同于None
,但NULL
用于表示该函数引发了异常。
答案 2 :(得分:2)
因为Python函数,即使只是打印到stdout的微不足道的函数,也不仅仅是围绕C函数的包装器。
在最简单的情况下,考虑Python中的内省设施。 Python函数是一个完整的对象,您可以查询:
>>> def hello():
... print 'hello'
...
>>> dir(hello)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
你当然可以设想一个只包含C函数的扩展工具。
查看SWIG,它允许您编写许多脚本语言的扩展,包括Python。因为它是最低的共同点,所以它会让你像hello_world
一样包裹一个函数,但当然你也失去了很多力量。