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