Supplemental integration examples

Last update: 8/11/97

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.

  1. More on calling objects (built-in API)
  2. Calling objects with the extended API
  3. More on running code strings (built-in API)
  4. Running code strings with the extended API
  5. Registering code (objects) through an extension

More on calling objects (built-in API)

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

Calling objects with the extended API

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);
}

More on running code strings (built-in API)

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!

Running code strings with the extended API

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");
}

Registering code (objects) through an extension

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



AltStyle によって変換されたページ (->オリジナル) /