Skip to content

Instantly share code, notes, and snippets.

@physacco
Last active December 27, 2023 09:05
Show Gist options
  • Save physacco/2e1b52415f3a964ad2a542a99bebed8f to your computer and use it in GitHub Desktop.
Save physacco/2e1b52415f3a964ad2a542a99bebed8f to your computer and use it in GitHub Desktop.
Python 3 extension example
#include <stdio.h>
#include <Python.h>
// Module method definitions
static PyObject* hello_world(PyObject *self, PyObject *args) {
printf("Hello, world!\n");
Py_RETURN_NONE;
}
static PyObject* hello(PyObject *self, PyObject *args) {
const char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return NULL;
}
printf("Hello, %s!\n", name);
Py_RETURN_NONE;
}
// Method definition object for this extension, these argumens mean:
// ml_name: The name of the method
// ml_meth: Function pointer to the method implementation
// ml_flags: Flags indicating special features of this method, such as
// accepting arguments, accepting keyword arguments, being a
// class method, or being a static method of a class.
// ml_doc: Contents of this method's docstring
static PyMethodDef hello_methods[] = {
{
"hello_world", hello_world, METH_NOARGS,
"Print 'hello world' from a method defined in a C extension."
},
{
"hello", hello, METH_VARARGS,
"Print 'hello xxx' from a method defined in a C extension."
},
{NULL, NULL, 0, NULL}
};
// Module definition
// The arguments of this structure tell Python what to call your extension,
// what it's methods are and where to look for it's method definitions
static struct PyModuleDef hello_definition = {
PyModuleDef_HEAD_INIT,
"hello",
"A Python module that prints 'hello world' from C code.",
-1,
hello_methods
};
// Module initialization
// Python calls this function when importing your extension. It is important
// that this function is named PyInit_[[your_module_name]] exactly, and matches
// the name keyword argument in setup.py's setup() call.
PyMODINIT_FUNC PyInit_hello(void) {
Py_Initialize();
return PyModule_Create(&hello_definition);
}
#!/usr/bin/env python3
# encoding: utf-8
from distutils.core import setup, Extension
hello_module = Extension('hello', sources = ['hello.c'])
setup(name='hello',
version='0.1.0',
description='Hello world module written in C',
ext_modules=[hello_module])
Copy link

ghost commented Aug 17, 2017

A great little example. Thanks.

@s2339956
Copy link

Thank you

@tryabin
Copy link

tryabin commented Oct 20, 2017

Thanks, went through several examples and this one was the first that worked for me.

@hannah-leitheiser
Copy link

Thank you!

@SidChenTW
Copy link

The sample code also works in Windows environment.
Thank you.

@purple4reina
Copy link

Can also do a pip install -e .

Thanks a ton!

@Arumugamvasu
Copy link

It's working good.

Hi ...i am not very familiar with c extension for python.I have some array calculation coding with c extension.but That's not working fine .am got some error when compile that code .anyone can help me...

I am currently trying to implement array multiplication with some formula in c .but don't really know how I would create empty array with input dimension and how to return from c function to extension main function.

My c code return array to main function.
#include "chie.h"

double chie(double m, double b, double *x, double *y, double *yerr, int N,double *result) {
int n;
double diff;
//double result = 0.0;
//static double result[5];
for (n = 0; n < N; n++) {
diff = (y[n] - (m * x[n] + b)) / yerr[n];
result[n]= diff * diff;
}

//return result;

}

then how to i catch the c array returned data to empty array.
this is my c extension main code.

#include <Python.h>
#include <numpy/arrayobject.h>
#include "chie.h"

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

static char module_docstring[] =
"This module provides an interface for calculating chi-squared using C.";
static char chie_docstring[] =
"Calculate the chi-squared of some data given a model.";

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

static PyObject *chi2_chi2(PyObject *self, PyObject *args)
{
double m, b;
PyObject *x_obj, *y_obj, *yerr_obj;
double *result[5];

/* 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. */
chie(m, b, x, y, yerr, N,result);

/* 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 */
return PyArray_Return(result);
//PyObject *ret = Py_BuildValue("d", result);
//return ret;

}

static PyMethodDef module_methods[] = {
{"chie", chi2_chi2, METH_VARARGS, chie_docstring},
{NULL, NULL, 0, NULL}
};

static struct PyModuleDef cieModule = {
PyModuleDef_HEAD_INIT,
"cieModule",
"example Module",
-1,
module_methods
};

/*PyMODINIT_FUNC PyInit_myexamp_Module(void)
{
return PyModule_Create(&myexamp_Module);
import_array();
}
*/
PyMODINIT_FUNC PyInit_cieModule(void)
{
PyObject *m;
m = PyModule_Create(&cieModule);
if (!m) {
return NULL;
}
import_array();
return m;
}

@burbilog
Copy link

Great!

@NMO13
Copy link

NMO13 commented Sep 26, 2019

Really nice!

@Doug3579
Copy link

This demo seems to be written for macintosh. Will it works on Windows? Either way, it would be helpful to mention it in the readme and possibly in the title.

Thanks!

@mga010
Copy link

mga010 commented Jun 24, 2020

Maybe someone here can help me. I do not only want to create a module in C, I also want to use it in C. The following code, however, shows that my embedded method is not read.

#include <stdio.h>
#include <Python.h>

const char* pystart = 
"print('Start')\n\
import eumat\n\
print(dir(eumat))\n\
print(eumat.test())";

static PyObject* ftest (PyObject* self, PyObject* args)
{
	return PyLong_FromLong(1000);
}

static PyMethodDef EmbMethods[] = {
	{
		"test", (PyCFunction)ftest, METH_NOARGS,"Test Function"
	},
	{NULL, NULL, 0, NULL}
};

int main()
{
	printf("Test Programm for Python 3.8\n");

	Py_Initialize();

	static struct PyModuleDef moduledef = {
		PyModuleDef_HEAD_INIT,
		"eumat",
		PyDoc_STR("EMT Module"),
		-1,
		EmbMethods
	};

	PyObject* eumat = PyModule_Create(&moduledef);
	if (!eumat)
	{
		printf("Could not create eumat module in Python.");
		return 0;
	}

	PyObject* pModule = PyImport_AddModule("eumat"); //create main module
	if (!pModule)
	{
		printf("Could not add the module eumat in Python.");
		return 0;
	}

	if (PyRun_SimpleString(pystart) == -1)
	{
		printf("Could not run pystart.");
		return 0;
	}

	return 1;
}

/*
Test Programm for Python 3.8
Start
['__doc__', '__loader__', '__name__', '__package__', '__spec__']
Traceback (most recent call last):
  File "", line 4, in 
AttributeError: module 'eumat' has no attribute 'test'
Could not run pystart.
C:\Users\reneg\source\repos\HalloWorld\x64\Release\HalloWorld.exe (process 30676) exited with code 0.
Press any key to close this window . . .
*/

@mga010
Copy link

mga010 commented Jun 26, 2020

Just for the records, I solved it:

#include <stdio.h>
#include <Python.h>

const char* pystart = 
"print('Start')\n\
import eumat\n\
print(dir(eumat))\n\
print(eumat.test())";

static PyObject* ftest (PyObject* self, PyObject* args)
{
	return PyLong_FromLong(1000);
}

static PyMethodDef EmbMethods[] = {
	{
		"test", (PyCFunction)ftest, METH_NOARGS,"Test Function"
	},
	{NULL, NULL, 0, NULL}
};

int main()
{
	printf("Test Programm for Python 3.8\n");

	Py_Initialize();

	static struct PyModuleDef moduledef = {
		PyModuleDef_HEAD_INIT,
		"eumat",
		PyDoc_STR("EMT Module"),
		-1,
		EmbMethods
	};


	PyObject* eumat = PyImport_AddModule("eumat"); //create main module
	if (!eumat)
	{
		printf("Could not add the module eumat in Python.");
		return 0;
	}

	PyModule_AddFunctions(eumat, EmbMethods);

	if (PyRun_SimpleString(pystart) == -1)
	{
		printf("Could not run pystart.");
		return 0;
	}

	return 1;
}

@wahaha233333
Copy link

Thanks bro!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment