Appendix Material

This page contains supplemental material for this March 1997 presentation. It includes directions for running the installed Python interpreter, and a few extra Python/C(++) integration examples not included in the original talk. Some of this was derived from a page I kept for a company I worked at, but it's mostly general information.

Update: also see the new integration examples page.

Content links


Running Python

Where Python lives

Important links



An example run script

The following csh script shows how to configure the Python (and Tk) environment variables:

file: runpy
#!/bin/csh
#
# file: runpy
# Give this file executable privileges (chmod +x runpy).
# You could also put the set/setenv's in your .cshrc instead.
#
# 1) Add path to command-line interpreter
set path = (/opt/local/sparc-solaris-2.4/bin $path)
 
# 2) Set python library search paths
# not really needed -> standard paths are hard-coded in interpreter
# add your module file working directories to the list as desired 
setenv PYTHONPATH /opt/local/lib/python1.4:/opt/local/lib/python1.4/tkinter

# 3) Set tk library search paths (for GUIs)
setenv TCL_LIBRARY /opt/local/lib/tcl7.4
setenv TK_LIBRARY  /opt/local/lib/tk4.0

# 4) Start up the command-line
python1.4


Now, run the command-line interpreter from the UNIX shell like this, and type in Python statements and expressions:

zppa% runpy
Python 1.4 (Mar  6 1997)  [GCC 2.7.2]
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> 
>>> from Tkinter import *
>>> w = Button(text="Hello", command='exit')
>>> w.pack()
>>> w.mainloop()


If everything is set up right, you'll get a simple 1-button window on your X display (what $DISPLAY names). Of course, this is just one way to run Python. You can also assign the environment variables in your .cshrc/.kshrc file, and/or:

Note: start-up details differ on Windows and Macs; see the section on ways to run Python programs in the talk material.


Extending Python in C/C++



A simple C extension module

The file below implements a C extension module for Python, called "environ". It wraps the C library's getenv routine for use in Python programs like this:

>>> import environ
>>> name = environ.getenv("USER")

To bind it into Python, add a line to Modules/Setup like "environ environ.c", put (or link) the file in Modules, and re-make python. Alternatively, compile to a .so, and add its path to $PYTHONPATH (dynamically loads when first imported).

file: environ.c
#include <Python.h>
#include <stdlib.h>


/* Functions */

static PyObject *                                 /* returns object */
wrap_getenv(PyObject *self, PyObject *args)       /* self not used */
{                                                 /* args from python */
    char *varName, *varValue;
    PyObject *returnObj = NULL;                         /* null=exception */

    if (PyArg_Parse(args, "s", &varName))               /* Python -> C */
        if ((varValue = getenv(varName)) != NULL)       /* call C getenv */
            returnObj = Py_BuildValue("s", varValue);   /* C -> Python */
        else 
            PyErr_SetString(PyExc_SystemError, "Error calling getenv");
    else
        PyErr_SetString(PyExc_TypeError, "Usage: getenv(varName)");
    return returnObj; 
}


/* Registration */

static struct PyMethodDef environ_methods[] = {
    {"getenv", wrap_getenv},        /* name, address */
    {NULL, NULL}
};


/* Initialization */

void initenviron()                  /* this is called by Python  */
{                                   /* on first "import environ" */
    (void) Py_InitModule("environ", environ_methods);
}

Things to add here...


Embedding Python in C/C++



Running simple code strings

file: embed.c
#include <Python.h>

main(argc, argv)
int argc;
char **argv;
{
    /* This is the simplest embedding mode.  */
    /* Other API functions return results,   */
    /* accept namespace arguments, allow     */
    /* access to real Python objects, etc.   */
    /* Strings may be precompiled for speed. */

    Py_Initialize();                                     /* initialize python */
    PyRun_SimpleString("print 'Hello embedded world!'"); /* run  python code */

    /* use C extension module above */
    PyRun_SimpleString("from environ import *"); 
    PyRun_SimpleString(
           "for i in range(5):\n"
                "\tprint i,\n"
                "\tprint 'Hello, %s' % getenv('USER')\n\n" );

    PyRun_SimpleString("print 'Bye embedded world!'");
}

char *Py_GetProgramName() { return "embed"; }    /* not always needed */


file: Makefile
PY = /opt/local/src/Python-1.4-embed/Python-1.4

PLIBS = $(PY)/Modules/libModules.a \
        $(PY)/Python/libPython.a \
        $(PY)/Objects/libObjects.a \
        $(PY)/Parser/libParser.a

POBJS = $(PY)/Modules/config.o $(PY)/Modules/getpath.o

embed:	embed.o
	cc embed.o $(POBJS) $(PLIBS) -lm -o embed

embed.o: embed.c
	cc embed.c -c -I$(PY)/Include -I$(PY)/.

Calling objects and methods: the hard way

Here's one way to do it using builtin API calls, less the error checking that you should normally do after each "Py*" API call. Check for NULL pointer results, etc., to detect errors in Python. Link with Python .a/.o's, and put module.py's dir in PYTHONPATH.

file: module.py

class klass:
    def method(self, x, y): 
        return "brave %s %s" % (x, y)   # run me from C


file: mymain1.c
#include <Python.h>
#include <import.h>
#include <stdio.h>
char *Py_GetProgramName() { return "mymain1"; }

main() {
  char *arg1="sir", *arg2="robin", *cstr;
  PyObject *pmod, *pclass, *pargs, *pinst, *pmeth, *pres;

  /* make module.class instance */
  Py_Initialize();
  pmod   = PyImport_ImportModule("module");         /* fetch module */
  pclass = PyObject_GetAttrString(pmod, "klass");   /* fetch module.class */
  Py_DECREF(pmod);

  pargs  = Py_BuildValue("()");
  pinst  = PyEval_CallObject(pclass, pargs);        /* call class() */
  Py_DECREF(pclass);
  Py_DECREF(pargs);
  
  /* call instance.method */
  pmeth  = PyObject_GetAttrString(pinst, "method"); /* fetch bound method */
  Py_DECREF(pinst);
  pargs  = Py_BuildValue("(ss)", arg1, arg2);       /* convert to Python */
  pres   = PyEval_CallObject(pmeth, pargs);         /* call method(x,y) */
  Py_DECREF(pmeth);
  Py_DECREF(pargs);

  PyArg_Parse(pres, "s", &cstr);                    /* convert to C */
  printf("%s\n", cstr);
  Py_DECREF(pres);
}

% mymain1
brave sir robin

Calling objects and methods: the easy way

This version uses the pyembed higher-level embedding interface. The interface also includes code string calls, etc. This approach can be simpler (especially if you add all the error detection logic to the example above). Compile with the "pyembed*.c" files from the book "Programming Python", chapter 15.

file: mymain2.c
#include <stdio.h>
#include "pyembed.h"
char *Py_GetProgramName() { return "mymain2"; }

main () {
  int status;
  PyObject *pinst;
  char *arg1="sir", *arg2="robin", *cstr;

  status = Run_Function("module", "klass", "O", &pinst, "()");
  status = Run_Method(pinst, "method", "s", &cstr, "(ss)", arg1, arg2);

  printf("%s\n", cstr);
  Py_DECREF(pinst);
}

% mymain2
brave sir robin

Things to add here...


Back to talk material root page



[Home page] Books Code Blog Python Author Train Find ©M.Lutz