Read Programming Python Online

Authors: Mark Lutz

Tags: #COMPUTERS / Programming Languages / Python

Programming Python (201 page)

BOOK: Programming Python
3.18Mb size Format: txt, pdf, ePub
ads
Using Python Classes in C

Earlier in this chapter,
we learned how to use C++ classes in Python by wrapping them
with SWIG. But what about going the other way—using Python classes from
other languages? It turns out that this is really just a matter of
applying interfaces already shown.

Recall that Python scripts generate class instance objects by
calling
class objects as though they were functions.
To do this from C (or C++), simply follow the same steps: import a class
from a module, build an arguments tuple, and call it to generate an
instance using the same C API tools you use to call Python functions. Once
you’ve got an instance, you can fetch its attributes and methods with the
same tools you use to fetch globals out of a module. Callables and
attributes work the same everywhere they live.

To illustrate how this works in practice,
Example 20-33
defines a simple Python
class in a module that we can utilize from C.

Example 20-33. PP4E\Integrate\Embed\Pyclasss\module.py

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

This is nearly as simple as it gets, but it’s enough to illustrate
the basics. As usual, make sure that this module is on your Python search
path (e.g., in the current directory, or one listed on your
PYTHONPATH
setting), or else the import call to
access it from C will fail, just as it would in a Python script. As you
surely know if you’ve gotten this far in this book, you can make always
use of this Python class from a Python program as follows:

...\PP4E\Integrate\Embed\Pyclass$
python
>>>
import module
# import the file
>>>
object = module.klass()
# make class instance
>>>
result = object.method('sir', 'robin')
# call class method
>>>
print(result)
brave sir robin

This is fairly easy stuff in Python. You can do all of these
operations in C, too, but it takes a bit more code. The C file in
Example 20-34
implements these steps by
arranging calls to the appropriate Python API tools.

Example 20-34. PP4E\Integrate\Embed\Pyclass\objects.c

#include 
#include
main() {
/* run objects with low-level calls */
char *arg1="sir", *arg2="robin", *cstr;
PyObject *pmod, *pclass, *pargs, *pinst, *pmeth, *pres;
/* instance = module.klass() */
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);
/* result = instance.method(x,y) */
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);
}

Step through this source file for more details; it’s mostly a matter
of figuring out how you would accomplish the task in Python, and then
calling equivalent C functions in the Python API. To build this source
into a C executable program, run the makefile in this file’s directory in
the book examples package (it’s analogous to makefiles we’ve already seen,
so we’ll omit it here). After compiling, run it as you would any other C
program:

.../PP4E/Integrate/Embed/Pyclass$
./objects
brave sir robin

This output might seem anticlimactic, but it actually reflects the
return values sent back to C by the Python class method in file
module.py
. C did a lot of work to get this little
string—it imported the module, fetched the class, made an instance, and
fetched and called the instance method with a tuple of arguments,
performing data conversions and reference count management every step of
the way. In return for all the work, C gets to use the techniques shown in
this file to reuse
any
Python class.

Of course, this example could be more complex in practice. As
mentioned earlier, you generally need to check the return value of every
Python API call to make sure it didn’t fail. The module import call in
this C code, for instance, can fail easily if the module isn’t on the
search path; if you don’t trap the
NULL
pointer result, your program will almost certainly crash when it tries to
use the pointer (at least eventually).
Example 20-35
is a recoding of
Example 20-34
with full error-checking;
it’s big, but it’s robust.

Example 20-35. PP4E\Integrate\Embed\Pyclasss\objects-err.c

#include 
#include
#define error(msg) do { printf("%s\n", msg); exit(1); } while (1)
main() {
/* run objects with low-level calls and full error checking */
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);
}

These 53 lines of C code (not counting its makefile) achieve the
same results as the
4 lines
of
interactive Python we ran earlier—not exactly a stellar result from a
developer productivity perspective! Nevertheless, the model it uses allows
C and C++ to leverage Python in the same way that Python can employ C and
C++. As I’ll discuss in this book’s conclusion in a moment, such
combinations can often be more powerful than their
individual parts.

Other Integration Topics

In this chapter, the term
integration
has
largely meant mixing Python with components written in C or C++ (or other
C-compatible languages) in extending and embedding modes. But from a
broader perspective, integration also includes any other technology that
lets us mix Python components into larger, heterogeneous systems. To wrap
up this chapter, this last section briefly summarizes a handful of
commonly used integration technologies beyond the C API tools we’ve
explored.

Jython: Java integration

We first
met Jython in
Chapter 12
and
it was discussed earlier in this chapter in the context of
extending. Really, though, Jython is a broader integration platform.
Jython compiles Python code to Java bytecode for execution on the
JVM. The resulting Java-based system directly supports two kinds of
integration:

  • Extending
    : Jython uses Java’s
    reflection API
    to allow Python programs to
    call out to Java class libraries automatically. The Java
    reflection API provides Java type information at runtime and
    serves the same purpose as the glue code we’ve generated to plug
    C libraries into Python in this part of the book. In Jython,
    however, this runtime type information allows largely automated
    resolution of Java calls in Python scripts—no glue code has to
    be written or generated.

  • Embedding
    : Jython also provides a
    Java
    PythonInterpreter
    class API that allows Java programs to run Python
    code in a namespace, much like the C API tools we’ve used to run
    Python code strings from C programs. In addition, because Jython
    implements all Python objects as instances of a Java
    PyObject
    class, it is straightforward
    for the Java layer that encloses embedded Python code to process
    Python objects.

In other words, Jython allows Python to be both extended and
embedded in Java, much like the C integration strategies we’ve seen
in this part of the book. By adding a simpler scripting language to
Java applications, Jython serves many of the same roles as the C
integration tools we’ve studied.

On the downside, Jython tends to lag behind CPython
developments, and its reliance on Java class libraries and execution
environments introduces Java dependencies that may be a factor in
some Python-oriented development scenarios. Nevertheless, Jython
provides a remarkably seamless integration model and serves as an
ideal scripting language for Java applications. For more on Jython,
check it out online at
http://www.jython.org
and search the Web at large.

IronPython: C#/.NET integration

Also
mentioned earlier, IronPython does for C#/.NET what
Jython does for Java (and in fact shares a common inventor)—it
provides seamless integration between Python code and software
components written for the .NET framework, as well as its Mono
implementation on Linux. Like Jython, IronPython compiles Python
source code to the .NET system’s bytecode format and runs programs
on the system’s runtime engine. As a result, integration with
external components is similarly seamless. Also like Jython, the net
effect is to turn Python into an easy-to-use scripting language for
C#/.NET-based applications and a general-purpose rapid development
tool that complements C#. For more details on IronPython, visit
http://www.ironpython.org
or your friendly
neighborhood search engine.

COM integration on Windows

COM
defines a standard and language-neutral object model
with which components written in a variety of programming languages
may integrate and communicate. Python’s PyWin32 Windows extension
package allows Python programs to implement both server and client
in the COM interface model. As such, it provides an automated way to
integrate Python programs with programs written in other COM-aware
languages such as Visual Basic. Python scripts can also use COM
calls to script Microsoft applications such as Word and Excel,
because these systems register COM object interfaces. On the other
hand, COM implies a level of dispatch indirection overhead and is
not as platform agnostic as other approaches listed here. For more
information on COM support and other Windows extensions, see the Web
and refer to O’Reilly’s
Python Programming
on Win32
, by Mark Hammond and Andy
Robinson.

CORBA integration

There is
also much open source support for using Python in the
context of a CORBA-based application.
CORBA
stands for the Common Object Request Broker; it’s a language-neutral
way to distribute systems among communicating components, which
speak through an object model architecture. As such, it represents
another way to integrate Python components into a larger system.
Python’s CORBA support includes public domain systems such OmniORB.
Like COM, CORBA is a large system—too large for us to even scratch
the surface in this text. For more details, search the Web.

Other languages

As we discussed at the end of our extending coverage, you’ll
also find direct support for mixing Python with other languages,
including FORTRAN, Objective-C, and others. Many support both
extending (calling out to the integrated languages) as well as
embedding (handling calls from the integrated language). See the
prior discussion and the Web for more details. Some observers might
also include the emerging pyjamas system in this category—by
compiling Python code to JavaScript code, it allows Python programs
to access AJAX and web browser–based APIs in the context of the Rich
Internet Applications discussed earlier in this book; see Chapters
7
,
12
, and
16
.

Network-based integration protocols

Finally, there is also support in the Python world for
Internet-based data transport protocols, including
SOAP, and
XML-RPC. By routing calls across networks such systems
support distributed architectures, and give rise to the notion of
web services. XML-RPC is supported by a standard library module in
Python, but search the Web for more details on these
protocols.

As you can see, there are many options in the integration domain.
Perhaps the best parting advice I can give you is simply that different
tools are meant for different tasks. C extension modules and types are
ideal at optimizing systems and integrating libraries, but frameworks
offer other ways to integrate components—Jython and IronPython for using
Java and .NETs, COM for reusing and publishing objects on Windows, XML-RPC
for distributed services, and so on. As always, the best tools for your
programs will almost certainly be the best tools for your programs.

BOOK: Programming Python
3.18Mb size Format: txt, pdf, ePub
ads

Other books

Blood Before Sunrise by Amanda Bonilla
Looking for Mrs Dextrose by Nick Griffiths
Soccer Duel by Matt Christopher
Swordsman of Lost Terra by Poul Anderson
Check Mate by Beverly Barton
GUNNED by Macko, Elaine
Be Mine by Jennifer Crusie