How to wrap C code in Python
#include <Python.h> | |
#include <numpy/arrayobject.h> | |
#include "chi2.h" | |
/* Docstrings */ | |
static char module_docstring[] = | |
"This module provides an interface for calculating chi-squared using C."; | |
static char chi2_docstring[] = | |
"Calculate the chi-squared of some data given a model."; | |
/* Available functions */ | |
static PyObject *chi2_chi2(PyObject *self, PyObject *args); | |
/* Module specification */ | |
static PyMethodDef module_methods[] = { | |
{"chi2", chi2_chi2, METH_VARARGS, chi2_docstring}, | |
{NULL, NULL, 0, NULL} | |
}; | |
/* Initialize the module */ | |
PyMODINIT_FUNC init_chi2(void) | |
{ | |
PyObject *m = Py_InitModule3("_chi2", module_methods, module_docstring); | |
if (m == NULL) | |
return; | |
/* Load `numpy` functionality. */ | |
import_array(); | |
} | |
static PyObject *chi2_chi2(PyObject *self, PyObject *args) | |
{ | |
double m, b; | |
PyObject *x_obj, *y_obj, *yerr_obj; | |
/* Parse the input tuple */ | |
if (!PyArg_ParseTuple(args, "ddOOO", &m, &b, &x_obj, &y_obj, | |
&yerr_obj)) | |
return NULL; | |
/* Interpret the input objects as numpy arrays. */ | |
PyObject *x_array = PyArray_FROM_OTF(x_obj, NPY_DOUBLE, NPY_IN_ARRAY); | |
PyObject *y_array = PyArray_FROM_OTF(y_obj, NPY_DOUBLE, NPY_IN_ARRAY); | |
PyObject *yerr_array = PyArray_FROM_OTF(yerr_obj, NPY_DOUBLE, | |
NPY_IN_ARRAY); | |
/* If that didn't work, throw an exception. */ | |
if (x_array == NULL || y_array == NULL || yerr_array == NULL) { | |
Py_XDECREF(x_array); | |
Py_XDECREF(y_array); | |
Py_XDECREF(yerr_array); | |
return NULL; | |
} | |
/* How many data points are there? */ | |
int N = (int)PyArray_DIM(x_array, 0); | |
/* Get pointers to the data as C-types. */ | |
double *x = (double*)PyArray_DATA(x_array); | |
double *y = (double*)PyArray_DATA(y_array); | |
double *yerr = (double*)PyArray_DATA(yerr_array); | |
/* Call the external C function to compute the chi-squared. */ | |
double value = chi2(m, b, x, y, yerr, N); | |
/* Clean up. */ | |
Py_DECREF(x_array); | |
Py_DECREF(y_array); | |
Py_DECREF(yerr_array); | |
if (value < 0.0) { | |
PyErr_SetString(PyExc_RuntimeError, | |
"Chi-squared returned an impossible value."); | |
return NULL; | |
} | |
/* Build the output tuple */ | |
PyObject *ret = Py_BuildValue("d", value); | |
return ret; | |
} |
This comment has been minimized.
This comment has been minimized.
Nice code however what if my module does not need fucntions but need to do something like this where it calls classes from a from importlib.machinery import FileFinder
from ._pycx_backend import *
import sys
extension_importers = [JsonImporter(), PycxImporter()]
hook_list = []
for importer in extension_importers:
hook_list.append((importer.find_loader, importer.extensions))
sys.path_hooks.insert(0, FileFinder.path_hook(*hook_list))
sys.path_importer_cache.clear() Basically I want to write this in using C Code similar to how you wrote this without using all too annoying Cython because it is entirely unreadable. |
This comment has been minimized.
This comment has been minimized.
Can't get it work on Python3.6. Importing in REPL tells me that Py_InitModule3 Edit: Confirmed its initialization function outdated. Here is the updated gist from StackOverflow: https://gist.github.com/GreenJoey/b08528d6abe62da70f28f73c39c0efd0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
How about a ctypes version: https://gist.github.com/3313315 ...