Argument passing in Python module written in C

最后都变了- 提交于 2019-12-06 15:24:29

问题


I have been getting my feet wet with writing Python modules in C. I've started with just a simple example of computing the norm of two points. The code looks like this,

_norm.c

#include <Python.h>
#include "norm.h"

static char module_docstring[] =
    "This module provides an interface for computing the norm using C.";
static char norm_docstring[] =
    "Calculate the norm between two points";
static char norm2_docstring[] =
    "Calculate the square norm between two points. For efficiency.";

static PyObject *norm_norm(PyObject *self, PyObject *args);

static PyObject *norm_norm2(PyObject *self, PyObject *args);

static PyMethodDef module_methods[] = {
    {"norm", norm_norm, METH_VARARGS, norm_docstring},
    {"norm2", norm_norm2, METH_VARARGS, norm2_docstring},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC init_norm(void) {
    PyObject *m = Py_InitModule3("_norm", module_methods, module_docstring);
    if (m == NULL)
        return;
}

static PyObject *norm_norm(PyObject *self, PyObject *args) {
   double x1, y1, x2, y2;
   /* Parse the input tuple */
   if (!PyArg_ParseTuple(args, "ddOOO", &x1, &y1, &x2, &y2))
       return NULL;

/* Call the external C function to compute the norm. */
double value = norm(x1, y1, x2, y2);

if (value < 0.0) {
    PyErr_SetString(PyExc_RuntimeError,
                    "Norm returned an impossible value.");
}
PyObject *ret = Py_BuildValue("d", value);
return ret;
}

norm.c

#include <math.h>

long double norm2(long double x1, long double y1, long double x2, long double y2) {
    long double xd = x2 - x1;
    long double yd = y2 - y1;
    return xd * xd + yd * yd;
}

long double norm(long double x1, long double y1, long double x2, long double y2) {
    return sqrt(norm2(x1, y1, x2, y2));
}

setup.py

from distutils.core import setup, Extension

setup(
    ext_modules=[Extension("_norm", ["_norm.c", "norm.c"])]
)

I build the package like this,

python setup.py build_ext --inplace

And it compiles with no problems. However, when I try to use it I get an error about the number of arguments.

>>> import _norm
>>> _norm.norm(1,2,5,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function takes exactly 5 arguments (4 given)

I guess it might have something to do with the declaration of PyObject *norm_norm() because it gets passed *self, but I'm not sure if that should effect the arguments that I pass to the module on the Python side of things. I'd appreciate any help/suggestions.


回答1:


The problem in the format string of PyArg_ParseTuple. You are trying to extract four double arguments, but the format string is for two double arguments and three arbitrary Python objects ("ddOOO").

The correct format string should be "dddd" for what you are trying to do. Change this

if (!PyArg_ParseTuple(args, "ddOOO", &x1, &y1, &x2, &y2))

with

if (!PyArg_ParseTuple(args, "dddd", &x1, &y1, &x2, &y2))



来源:https://stackoverflow.com/questions/24661141/argument-passing-in-python-module-written-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!