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.
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