While you would normally create the C portions of a Python module in a separate library, there are however some instances where a separate library might not be desirable.
In this example, a script will be run which can use functions that are part of the embedding application, lets take a look at the python script
# test.py import funcMod def main(text, i, j): print ('Passed to python "'+text+'" : '+str(i)+' : '+str(j) ) print ('mod = '+str(funcMod.mod(i,j))) r = funcMod.func(i,j) return r
The module "funcMod" doesn't exist in the traditional sense, there are no files for Python to load when this module is imported. This module contains two functions "mod" and "func", that provide trivial functionality for the sake of example.
Before the Python module can be added to the interpreters state, it must be initialised so that Python knows not just what functions it has but also where the implementations are.
/* Module method table */ static PyMethodDef funcMethods[] = { {"func", func, METH_VARARGS, "Add two ints"}, {"mod", funcModulus, METH_VARARGS, "modulus"}, { NULL, NULL, 0, NULL} }; /* Module structure */ static struct PyModuleDef funcmodule = { PyModuleDef_HEAD_INIT, "funcMod", /* name of module */ "function module", /* Doc string (may be NULL) */ -1, /* Size of per-interpreter state or -1 */ funcMethods /* Method table */ };
The first structure details the function names and the functions they correspond to, as well as the function signature and document string. The second structure is more overall data regarding the module as a whole. The name of the module and a reference to the method table.
// create the function module PyObject* funcMod = PyModule_Create(&funcmodule); // add the module to the system modules so it can be imported PyObject* sys_modules = PyImport_GetModuleDict(); PyDict_SetItemString(sys_modules, "funcMod", funcMod); Py_DECREF(funcMod);
While actually creating the module is trivial, there is one minor wrinkle in that we need to "insert" the module into the interpreters list of built in modules.
The rest of the code (below) is entirely concerned with running a Python script and follows the normal pattern you'd expect when embedding Python in an application. While there are other reasons for creating a Python module "on the fly" one of the most useful features of this technique is that assuming you make your application self contained (statically linked) then it is entirely self contained, no custom module needs installing...
Enjoy!
// gcc -g $(python3-config --cflags --ldflags --embed) test.c -o test #include <Python.h> #include <stdlib.h> static PyObject* func(PyObject * self, PyObject * args) { int a, b, result; if (! PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } result = a + b; return Py_BuildValue("i", result); } static PyObject* funcModulus(PyObject * self, PyObject * args) { int a, b, result; if (! PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } result = a % b; return Py_BuildValue("i", result); } /* Module method table */ static PyMethodDef funcMethods[] = { {"func", func, METH_VARARGS, "Add two ints"}, {"mod", funcModulus, METH_VARARGS, "modulus"}, { NULL, NULL, 0, NULL} }; /* Module structure */ static struct PyModuleDef funcmodule = { PyModuleDef_HEAD_INIT, "funcMod", /* name of module */ "function module", /* Doc string (may be NULL) */ -1, /* Size of per-interpreter state or -1 */ funcMethods /* Method table */ }; int main() { // Set PYTHONPATH to the working directory setenv("PYTHONPATH",".",1); // Initialize the Python Interpreter Py_Initialize(); // create the function module PyObject* funcMod = PyModule_Create(&funcmodule); // add the module to the system modules so it can be imported PyObject* sys_modules = PyImport_GetModuleDict(); PyDict_SetItemString(sys_modules, "funcMod", funcMod); Py_DECREF(funcMod); // the name of the script to run PyObject* scriptName = PyUnicode_FromString((char*)"test"); // import the script PyObject* scriptModule = PyImport_Import(scriptName); if (!scriptModule) { PyErr_Print(); return -1; } // pDict is a borrowed reference, get all its functions PyObject* pDict = PyModule_GetDict(scriptModule); // pFunc is also a borrowed reference, the function to call PyObject* pFunc = PyDict_GetItemString(pDict, (char*)"main"); PyObject *pValue = NULL; // for the parameters PyObject *pResult = NULL; // value returned from the script if (PyCallable_Check(pFunc)) { // build the parameters pValue=Py_BuildValue("(z,i,i)",(char*)"Test string",(int*)37, (int*)5); PyErr_Print(); // finally call it. pResult=PyObject_CallObject(pFunc, pValue); PyErr_Print(); } else { PyErr_Print(); } // return value from the script printf("Result is %ld\n",PyLong_AsLong(pResult)); Py_DECREF(pValue); // Clean up Py_DECREF(scriptModule); Py_DECREF(scriptName); // Finish the Python Interpreter Py_Finalize(); return 0; }