This page contains a few additional Python/C integration examples which didn't make it into the first edition, but will probably show up in the second in one form or another (and/or in other publications before that).
For instance, the chapter on embedding (15) may be split into two: one on built-in API tools, and another on the extended API developed in the current chapter 15. The extended API was conceived as a way to teach basic embedding, but I'd like to make it more distinct in the next edition.
Note: there are no plans to start the second edition yet (and it will probably be a year or more before we even talk about it!), so please take these only as supplemental examples, not a preview.
task (in C) import module object = module.klass() result = object.method(..args..) file: module.py class klass: def method(self, x, y): return "brave %s %s" % (x, y) # run me from C file: objects1.c #include <Python.h> #include <import.h> #include <stdio.h> char *Py_GetProgramName() { return "objects1"; } #define error(msg) do { printf("%s\n", msg); exit(1); } while (1) main() { char *arg1="sir", *arg2="robin", *cstr; PyObject *pmod, *pclass, *pargs, *pinst, *pmeth, *pres; /* instance = module.klass() */ Py_Initialize(); pmod = PyImport_ImportModule("module"); /* fetch module */ if (pmod == NULL) error("Can't load module"); pclass = PyObject_GetAttrString(pmod, "klass"); /* fetch module.class */ Py_DECREF(pmod); if (pclass == NULL) error("Can't get module.klass"); pargs = Py_BuildValue("()"); if (pargs == NULL) { Py_DECREF(pclass); error("Can't build arguments list"); } pinst = PyEval_CallObject(pclass, pargs); /* call class() */ Py_DECREF(pclass); Py_DECREF(pargs); if (pinst == NULL) error("Error calling module.klass()"); /* result = instance.method(x,y) */ pmeth = PyObject_GetAttrString(pinst, "method"); /* fetch bound method */ Py_DECREF(pinst); if (pmeth == NULL) error("Can't fetch klass.method"); pargs = Py_BuildValue("(ss)", arg1, arg2); /* convert to Python */ if (pargs == NULL) { Py_DECREF(pmeth); error("Can't build arguments list"); } pres = PyEval_CallObject(pmeth, pargs); /* call method(x,y) */ Py_DECREF(pmeth); Py_DECREF(pargs); if (pres == NULL) error("Error calling klass.method"); if (!PyArg_Parse(pres, "s", &cstr)) /* convert to C */ error("Can't convert klass.method result"); printf("%s\n", cstr); Py_DECREF(pres); } % objects1 brave sir robin
Same task as above, but with the extended API in chapter 15.
file: objects2.c #include <stdio.h> #include "pyembed.h" char *Py_GetProgramName() { return "objects2"; } main () { int failflag; PyObject *pinst; char *arg1="sir", *arg2="robin", *cstr; failflag = Run_Function("module", "klass", "O", &pinst, "()") || Run_Method(pinst, "method", "s", &cstr, "(ss)", arg1, arg2); printf("%s\n", (!failflag) ? cstr : "Can't call objects"); Py_XDECREF(pinst); }
Run "upper('spam') + '!'" in string module's namespace.
file codestring1.c #include <Python.h> /* standard API defs */ #include <import.h> /* PyImport functions */ #include <graminit.h> /* parse-mode flags */ #include <pythonrun.h> /* PyRun interfaces */ char *Py_GetProgramName() { return "codestring1"; } void error(char *msg) { printf("%s\n", msg); exit(1); } main() { char *cstr; PyObject *pstr, *pmod, *pdict; /* with error tests */ Py_Initialize(); /* result = string.upper('spam') + '!' */ pmod = PyImport_ImportModule("string"); /* fetch module */ if (pmod == NULL) /* for name-space */ error("Can't import module"); pdict = PyModule_GetDict(pmod); /* string.__dict__ */ Py_DECREF(pmod); if (pdict == NULL) error("Can't get module dict"); pstr = PyRun_String("upper('spam') + '!'", eval_input, pdict, pdict); if (pstr == NULL) error("Error while running string"); /* convert result to C */ if (!PyArg_Parse(pstr, "s", &cstr)) error("Bad result type"); printf("%s\n", cstr); Py_DECREF(pstr); /* free exported objects, not pdict */ } % codestring1 SPAM!
Same task, but using extended API in chapter 15
file: codestring2.c #include "pyembed.h" #include <stdio.h> char *Py_GetProgramName() { return "codestring2"; } main() { char *cstr; int err = Run_Codestr( PY_EXPRESSION, /* expr or stmt? */ "upper('spam') + '!'", "string", /* code, module */ "s", &cstr); /* expr result */ printf("%s\n", (!err) ? cstr : "Can't run string"); }
Discussed abstractly near the end of chapter 15, but here's a concrete example. Note that this is just a way to locate embedded code to run; the code can be objects (as here), code strings, etc.
file: cregister.c #include <Python.h> #include <stdlib.h> /***********************************************/ /* 1) code to route events to Python object */ /* note that we could run strings here instead */ /***********************************************/ static PyObject *Handler = NULL; /* keep Python object in C */ void Route_Event(char *label, int count) { char *cres; PyObject *args, *pres; /* call Python handler */ args = Py_BuildValue("(si)", label, count); /* make arg-list */ pres = PyEval_CallObject(Handler, args); /* apply: run a call */ Py_DECREF(args); /* add error checks */ if (pres != NULL) { /* use and decref handler result */ PyArg_Parse(pres, "s", &cres); printf("%s\n", cres); Py_DECREF(pres); } } /*****************************************************/ /* 2) python extension module to register handlers */ /* python imports this module to set handler objects */ /*****************************************************/ static PyObject * Register_Handler(PyObject *self, PyObject *args) { /* save Python callable object */ Py_XDECREF(Handler); /* called before? */ PyArg_Parse(args, "O", &Handler); /* one argument? */ Py_XINCREF(Handler); /* add a reference */ Py_INCREF(Py_None); /* return 'None': success */ return Py_None; } static PyObject * Trigger_Event(PyObject *self, PyObject *args) { /* let Python simulate event caught by C */ static count = 0; Route_Event("spam", count++); Py_INCREF(Py_None); return Py_None; } static struct PyMethodDef cregister_methods[] = { {"setHandler", Register_Handler}, /* name, address */ {"triggerEvent", Trigger_Event}, {NULL, NULL} }; void initcregister() /* this is called by Python */ { /* on first "import cregister" */ (void) Py_InitModule("cregister", cregister_methods); } file: register.py # handle an event, return a result (or None) def function1(label, count): return "%s number %i..." % (label, count) def function2(label, count): return label * count # register handlers, trigger events import cregister cregister.setHandler(function1) for i in range(3): cregister.triggerEvent() # simulate events caught by C layer cregister.setHandler(function2) for i in range(3): cregister.triggerEvent() # routes these events to function2 % python register.py spam number 0... spam number 1... spam number 2... spamspamspam spamspamspamspam spamspamspamspamspam
Back to the errata page
Back to my homepage