Python C扩展模块中的无返回值方法

14 投票
2 回答
11366 浏览
提问于 2025-04-17 08:04

我正在尝试用Python写一个脚本,通过并行端口发送数据。我正在用C语言创建自己的模块。

问题是:当我尝试执行我的模块时,Python就崩溃了。没有错误提示,没有数据输出,什么都没有。它就是直接关闭了。

这是我的模块:

#include <Python.h>
#include <sys/io.h>
#define BaseAddr 0x378

/*----------------------------------------------------------------------------------
Este es un módulo destinado a controlar el puerto paralelo.
Probablemente tenga que ser ejecutado como administrador.

Created by markmb
------------------------------------------------------------------------------------*/

static PyObject *
paralelo(PyObject *self, PyObject *args){
    int pin;
    ioperm(BaseAddr,3,1);
    if (!PyArg_ParseTuple(args, "i", &pin))
        return NULL;
    outb(pin,BaseAddr);
    ioperm(BaseAddr,3,0);
    return 1
}
PyMethodDef methods[] = {
    {"paralelo", paralelo, METH_VARARGS, "Sends data through a parallel port"},
    {NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initparalelo(void){
    (void) Py_InitModule("paralelo", methods);
}

(在没有Python的那些麻烦时,它是可以工作的)我通过distutils编译它,然后在终端(使用xubuntu)中输入:

import paralelo
while True:
    paralelo.paralelo(255)

然后,它就退出了Python,显示“markmb@...”

提前谢谢你们!

2 个回答

23

所有的 Python 函数都应该返回一个 PyObject,除非它们想要抛出一个异常,具体解释可以参考这里:http://docs.python.org/extending/extending.html#intermezzo-errors-and-exceptions

你看到的错误信息 SystemError: error return without exception set 是在告诉你,你的函数返回了 NULL(也就是出错了,应该抛出一个异常),但没有告诉 Python 解释器你想抛出什么异常。

如果你不想从 Python 函数返回一个值,你可以让它返回 None(这和在 Python 代码中一个函数运行到最后或者简单地返回没有值是一样的)。

在 cpython 的 API 中,你可以通过返回 Py_None 对象来实现这一点,别忘了增加它的引用计数。为了帮助你记得增加引用计数,有一个宏可以帮你做到这一点:http://docs.python.org/c-api/none.html#Py_RETURN_NONE

所以,一个返回空值(也就是返回 None)的函数的基本结构看起来像这样:

static PyObject *
myfunction(PyObject *self, PyObject *args){
    if (!PyArg_ParseTuple(args, "i", ...))
        return NULL;
    /* .... */
    Py_RETURN_NONE;
}

最后,顺便提一下:已经有一个 Python 模块可以用来进行 ioperm/outb 调用:http://pypi.python.org/pypi/portio

13

在Python/C API中,返回NULL表示发生了错误。但是如果你没有真正设置一个异常,就会出现这个错误:

SystemError: error return without exception set

如果你想返回None,应该使用:

return Py_BuildValue("");

撰写回答