GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • on-line
  • website
  • binary executable release
  • install hints
  • /opt/local/src/Python-1.4-embed

This view

  • Original page
  • New address

GeezerVison is showing learning-python.com — Python Slides: Appendix Material

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
  • Extending Python in C/C++
  • Embedding Python in C/C++

Running Python

Where Python lives

  • UNIX install on Solaris in /opt/local, with Tk/Dbm support
  • MS-Windows binaries on the net and CD, both MFC and Tk versions
  • Macintosh binaries available on the net and CD too, with Tk support

Important links

  • Standard manuals on-line
  • Browse Python's website
  • Fetch files from Python's ftp site
  • A Windows95/NT Python+Tk binary executable release
  • More Windows95 Python+Tk install hints


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:

  • Run the "python" interpreter outside this script
  • Use the "#!/..." line to create executable Python script files
  • Or run Python code/objects from within a C/C++ program

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++

  • Purpose: optimization and integration
  • Structure: functions, registration, initialization
  • Tasks: reference counts, error handling
  • Linked in statically or dynamically (.o/Setup, .dll/.so)
  • C modules work just like Python module files
  • C types work like Python classes (but no inheritance)
  • Automatic tools: SWIG wrapper classes for C++ classes


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...

  • Writing extension types
  • C++ integration issues: wrappers, linking,..

Embedding Python in C/C++

  • Purpose: app extensions
  • Running code strings
  • Calling objects and methods
  • Using modules and namespaces
  • Link with Python libraries and .o's
  • See /opt/local/src/Python-1.4-embed
  • See "Programming Python" for more details


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...

  • Running code strings with results and namespaces
  • Handling Python errors in C/C++ (PyErr_Fetch: see Dmh examples)

Back to talk material root page



[Home page] Books Code Blog Python Author Train Find ©M.Lutz
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.