2012-04-21 33 views
7

我刚刚开始玩Python C扩展,并且很好奇为什么可以从Python调用的C函数必须使用2个PyObject *参数并返回一个PyObject *。我写了下面的 “Hello World” 扩展名:Python C扩展 - 为什么必须调用C函数需要参数并返回PyObject *

#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"); 
} 

回答

10

有几件事情要说一下各种PyObject指针。

  1. 需要作为返回类型该一个用于异常处理机制。具体来说,如果你的函数返回一个空指针,Python解释器将抛出一个异常。 (您只能做主叫的PyErr_..功能之一后设置一个特定的例外)。

    这也意味着,只要你不想抛出异常,你必须返回一个指针到一些真正的PyObject如果没有什么特别的功能应该返回,只需返回Py_None(最好使用Py_RETURN_NONE宏来获取引用计数)或“true”(使用Py_RETURN_TRUE)。

  2. 第一个参数,PyObject *self指向函数被调用的对象或它所属的模块实例。请注意,您定义的每个函数都是类方法或模块方法。没有完全独立的功能。

  3. 参数PyObject *args指向函数参数(可能是一个元组或多个参数列表)。你是对的,指出一个没有任何参数的函数不需要这个—,就我所知,你是对的。你不必定义它;你可以简单地定义一个函数为

    static PyObject *PyMyClass_MyFunc(PyObject *self) { 
        /* ..do something.. */ 
        Py_RETURN_TRUE; 
    } 
    

    你仍然必须投这PyCFunction当你把它放入PyMethodDef为数据类型定义,但我相信,投是安全的,只要你使用METH_NOARGS标志。 但请注意以下有关可能的风险的评论。

  4. 最后,函数实际上可能有一个第三个参数这样的:

    static PyObject *PyMyClass_Func(PyObject *self, PyObject *args, PyObject *kwds) 
    { 
        /*...*/ 
    } 
    

    第三个参数用于命名,可选参数。在这种情况下,您也必须使用将函数指针投射到PyCFunction,但如果在方法表中为您的函数设置了正确的标志(METH_KEYWORDS),那么也是安全的。

+0

它是'Py_None',而不是'PyNone'。还有'Py_RETURN_NONE'类似于'Py_RETURN_TRUE'和'Py_RETURN_FALSE'。 – yak 2012-04-21 10:09:41

+0

对于(3),纠正我,如果我错了,但如果代码使用调用约定,所有参数都在堆栈上传递,并且被调用者(函数)将它们从堆栈弹出,则删除未使用的参数会导致因为Python会一直通过NULL作为第二个参数,并且该函数不会弹出它。 – yak 2012-04-21 10:15:49

+0

@yak它不会导致我的代码崩溃。 – jogojapan 2012-04-21 10:16:57

2

因为Python功能,即使是微不足道的人,只是打印到标准输出,不仅仅是周围的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这样的功能,但是当然你也失去了很多的能力。

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用于指示该函数引发异常。

相关问题