This chapter describes SWIG's support of Python. SWIG is compatible with most recent Python versions including Python 2.2 as well as older versions dating back to Python 1.5. The original release of SWIG was developed for Python 1.3 so current versions may still work with that release. However, this hasn't been tested for quite some time and your mileage might vary. For the best results, consider using Python 2.0 or newer.
This chapter covers most SWIG features, but in less depth than is found in earlier chapters. At the very least, make sure you also read the "SWIG Basics" chapter.
If building a C++ extension, add the -c++ option:$ swig -python example.i
$ swig -c++ -python example.i
This creates a file example_wrap.c or example_wrap.cxx that contains all of the code needed to build a Python extension module. To finish building the module, you need to compile this file and link it with the rest of your program.
The exact location may vary on your machine, but the above location is typical. If you are not entirely sure where Python is installed, you can run Python to find out. For example:/usr/local/include/python2.0
$ python Python 2.1.1 (#1, Jul 23 2001, 14:36:06) [GCC egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> import sys >>> print sys.prefix /usr/local >>>
The exact commands for doing this vary from platform to platform. SWIG tries to guess the right options when it is installed. Therefore, you may want to start with one of the examples in the SWIG/Examples/python directory. If that doesn't work, you will need to read the man-pages for your compiler and linker to get the right set of options. You might also check the SWIG Wiki for additional information.$ swig -python example.i $ gcc -c example.c $ gcc -c example_wrap.c -I/usr/local/include/python2.0 $ gcc -shared example.o example_wrap.o -o examplemodule.so
When linking the module, the name of the output file has to match the name of the module. If the name of your SWIG module is "example", the name of the corresponding object file should be "examplemodule.so" or "example.so". The name of the module is specified using the %module directive or the -module command line option.
The usual procedure for adding a new module to Python involves finding the Python source, adding an entry to the Modules/Setup file, and rebuilding the interpreter using the Python Makefile. However, newer Python versions have changed the build process. You may need to edit the 'setup.py' file in the Python distribution instead.
In earlier versions of SWIG, the embed.i library file could be used to rebuild the interpreter. For example:
The embed.i library file includes supporting code that contains everything needed to rebuild Python. To rebuild the interpreter, you simply do something like this:%module example extern int fact(int); extern int mod(int, int); extern double My_variable; %include embed.i // Include code for a static version of Python
You will need to supply the same libraries that were used to build Python the first time. This may include system libraries such as -lsocket, -lnsl, and -lpthread. Assuming this actually works, the new version of Python should be identical to the default version except that your extension module will be a built-in part of the interpreter.$ swig -python example.i $ gcc example.c example_wrap.c \ -Xlinker -export-dynamic \ -DHAVE_CONFIG_H -I/usr/local/include/python2.1 \ -I/usr/local/lib/python2.1/config \ -L/usr/local/lib/python2.1/config -lpython2.1 -lm -ldl \ -o mypython
Comment: In practice, you should probably try to avoid static linking if possible. Some programmers may be inclined to use static linking in the interest of getting better performance. However, the performance gained by static linking tends to be rather minimal in most situations (and quite frankly not worth the extra hassle in the opinion of this author).
Compatibility note: The embed.i library file is deprecated and has not been maintained for several years. Even though it appears to "work" with Python 2.1, no future support is guaranteed. If using static linking, you might want to rely on a different approach (perhaps using distutils).
A common error received by first-time users is the following:$ python >>> import example >>> example.fact(4) 24 >>>
This error is almost always caused when the name of the shared object file doesn't match the name of the module supplied using the SWIG %module directive. Double-check the interface to make sure the module name and the shared object file match. Another possible cause of this error is forgetting to link the SWIG-generated wrapper code with the rest of your application when creating the extension module.>>> import example Traceback (most recent call last): File "", line 1, in ? ImportError: dynamic module does not define init function (initexample) >>>
Another common error is something similar to the following:
This error usually indicates that you forgot to include some object files or libraries in the linking of the shared library file. Make sure you compile both the SWIG wrapper file and your original program into a shared library file. Make sure you pass all of the required libraries to the linker.Traceback (most recent call last): File "example.py", line 3, in ? import example ImportError: ./examplemodule.so: undefined symbol: fact
Sometimes unresolved symbols occur because a wrapper has been created for a function that doesn't actually exist in a library. This usually occurs when a header file includes a declaration for a function that was never actually implemented or it was removed from a library without updating the header file. To fix this, you can either edit the SWIG input file to remove the offending declaration or you can use the %ignore directive to ignore the declaration.
Finally, suppose that your extension module is linked with another library like this:
If the foo library is compiled as a shared library, you might get the following problem when you try to use your module:$ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo \ -o examplemodule.so
This error is generated because the dynamic linker can't locate the libfoo.so library. When shared libraries are loaded, the system normally only checks a few standard locations such as /usr/lib and /usr/local/lib. To fix this problem, there are several things you can do. First, you can recompile your extension module with extra path information. For example, on Linux you can do this:>>> import example Traceback (most recent call last): File "", line 1, in ? ImportError: libfoo.so: cannot open shared object file: No such file or directory >>>
Alternatively, you can set the LD_LIBRARY_PATH environment variable to include the directory with your shared libraries. If setting LD_LIBRARY_PATH, be aware that setting this variable can introduce a noticeable performance impact on all other applications that you run. To set it only for Python, you might want to do this instead:$ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo \ -Xlinker -rpath /home/beazley/projects/lib \ -o examplemodule.so
Finally, you can use a command such as ldconfig to add additional search paths to the default system configuration (this requires root access and you will need to read the man pages).$ env LD_LIBRARY_PATH=/home/beazley/projects/lib python
On most machines, C++ extension modules should be linked using the C++ compiler. For example:
In addition to this, you may need to include additional library files to make it work. For example, if you are using the Sun C++ compiler on Solaris, you often need to add an extra library -lCrun like this:% swig -c++ -python example.i % g++ -c example.cxx % g++ -c example_wrap.cxx -I/usr/local/include/python2.0 % g++ -shared example.o example_wrap.o -o examplemodule.so
Of course, the extra libraries to use are completely non-portable---you will probably need to do some experimentation.% swig -c++ -python example.i % CC -c example.cxx % CC -c example_wrap.cxx -I/usr/local/include/python2.0 % CC -G example.o example_wrap.o -L/opt/SUNWspro/lib -o examplemodule.so -lCrun
Sometimes people have suggested that it is necessary to relink the Python interpreter using the C++ compiler to make C++ extension modules work. In the experience of this author, this has never actually appeared to be necessary. Relinking the interpreter with C++ really only includes the special run-time libraries described above---as long as you link your extension modules with these libraries, it should not be necessary to rebuild Python.
If you aren't entirely sure about the linking of a C++ extension, you might look at an existing C++ program. On many Unix machines, the ldd command will list library dependencies. This should give you some clues about what you might have to include when you link your extension module. For example:
$ ldd swig libstdc++-libc6.1-1.so.2 => /usr/lib/libstdc++-libc6.1-1.so.2 (0x40019000) libm.so.6 => /lib/libm.so.6 (0x4005b000) libc.so.6 => /lib/libc.so.6 (0x40077000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) $
As a final complication, a major weakness of C++ is that it does not define any sort of standard for binary linking of libraries. This means that C++ code compiled by different compilers will not link together properly as libraries nor is the memory layout of classes and data structures implemented in any kind of portable manner. In a monolithic C++ program, this problem may be unnoticed. However, in Python, it is possible for different extension modules to be compiled with different C++ compilers. As long as these modules are self-contained, this probably won't matter. However, if these modules start sharing data, you will need to take steps to avoid segmentation faults and other erratic program behavior. If working with lots of software components, you might want to investigate using a more formal standard such as COM.
To utilize 64-bits, the Python executable will need to be recompiled as a 64-bit application. In addition, all libraries, wrapper code, and every other part of your application will need to be compiled for 64-bits. If you plan to use other third-party extension modules, they will also have to be recompiled as 64-bit extensions.
If you are wrapping commercial software for which you have no source code, you will be forced to use the same linking standard as used by that software. This may prevent the use of 64-bit extensions. It may also introduce problems on platforms that support more than one linking standard (e.g., -o32 and -n32 on Irix).
In Developer Studio, SWIG should be invoked as a custom build option. This is usually done as follows:
If all went well, SWIG will be automatically invoked whenever you build your project. Any changes made to the interface file will result in SWIG being automatically executed to produce a new version of the wrapper file.
To run your new Python extension, simply run Python and use the import command as normal. For example :
If you get an ImportError exception when importing the module, you may have forgotten to include aditional library files when you built your module. If you get an access violation or some kind of general protection fault immediately upon import, you have a more serious problem. This is often caused by linking your extension module against the wrong set of Win32 debug or thread libraries. You will have to fiddle around with the build options of project to try and track this down.MSDOS > python >>> import example >>> print example.fact(4) 24 >>>
Some users have reported success in building extension modules using Cygwin and other compilers. However, the problem of building usable DLLs with these compilers tends to be rather problematic. For the latest information, you may want to consult the SWIG Wiki.
creates a built-in function example.fact(n) that works like this:%module example int fact(int n);
>>> import example >>> print example.fact(4) 24 >>>
"a" becomes a name for an object containing the value 3.4. If you later typea = 3.4
then "a" and "b" are both names for the object containing the value 3.4. Thus, there is only one object containing 3.4 and "a" and "b" are both names that refer to it. This is quite different than C where a variable name refers to a memory location in which a value is stored (and assignment copies data into that location). Because of this, there is no direct way to map variable assignment in C to variable assignment in Python.b = a
To provide access to C global variables, SWIG creates a special object called `cvar' that is added to each SWIG generated module. Global variables are then accessed as attributes of this object. For example, consider this interface
// SWIG interface file with global variables %module example ... extern int My_variable; extern double density; ...
Now look at the Python interface:
>>> import example >>> # Print out value of a C global variable >>> print example.cvar.My_variable 4 >>> # Set the value of a C global variable >>> example.cvar.density = 0.8442 >>> # Use in a math operation >>> example.cvar.density = example.cvar.density*1.10
If you make an error in variable assignment, you will receive an error message. For example:
>>> example.cvar.density = "Hello" Traceback (most recent call last): File "", line 1, in ? TypeError: C variable 'density (double )' >>>
If a variable is declared as const, it is wrapped as a read-only variable. Attempts to modify its value will result in an error.
To make ordinary variables read-only, you can also use the %readonly directive. For example:
The %readonly directive stays in effect until it is explicitly disabled using %readwrite.%readonly extern char *path; %readwrite
If you would like to use a name other than "cvar", it can be changed using the -globals option :
Finally, some care is in order when importing multiple SWIG modules. If you use the "from <file> import *" style of importing, you will get a name clash on the variable `cvar' and you will only be able to access global variables from the last module loaded. To prevent this, you might consider renaming cvar or making it private to the module by giving it a name that starts with a leading underscore. Also, SWIG does not create cvar if there are no global variables in a module.% swig -python -globals myvar example.i
Note: C declarations declared as const are wrapped as read-only variables and will be accessed using the cvar object described in the previous section. They are not wrapped as constants.#define PI 3.14159 #define VERSION "1.0" %constant int FOO = 42; %constant const char *path = "/usr/local";
Constants are not guaranteed to remain constant in Python---the name of the constant could be accidentally reassigned to refer to some other object. Unfortunately, there is no easy way for SWIG to generate code that prevents this. You will just have to be careful.
A NULL pointer is represented by the Python None object._800f8e28_p_Vector
As an alternative to strings, SWIG can also encode pointers as a Python CObject type. CObjects are rarely discussed in most Python books or documentation. However, this is a special built-in type that can be used to hold raw C pointer values. Internally, a CObject is just a container that holds a raw void * along with some additional information such as a type-string.
If you want to use CObjects instead of strings, compile the SWIG wrapper code with the -DSWIG_COBJECT_TYPES option. For example:
The choice of whether or not to use strings or CObjects is mostly a matter of personal preference. There is no significant performance difference between using one type or the other (strings actually appear to be ever-so-slightly faster on the author's machine). Although CObjects feel more natural to some programmers, a disadvantage of this approach is that it makes debugging more difficult. For example, if you are using CObjects, you will get code that works like this:% swig -python example.i % gcc -c example.c % gcc -c -DSWIG_COBJECT_TYPES example_wrap.c -I/usr/local/include/python2.0 % gcc -shared example.o example_wrap.o -o examplemodule.so
Notice how no clues regarding the type of a and b is shown. On the other hand, the string representation produces the following:>>> import example >>> a = example.new_Circle(10) >>> b = example.new_Square(20) >>> a <PyCObject object at 0x80c5e60> >>> b <PyCObject object at 0x8107800> >>>
As much as you might be inclined to modify a pointer value directly from Python, don't. The hexadecimal encoding is not necessarily the same as the logical memory address of the underlying object. Instead it is the raw byte encoding of the pointer value. The encoding will vary depending on the native byte-ordering of the platform (i.e., big-endian vs. little-endian). Similarly, don't try to manually cast a pointer to a new type by simply replacing the type-string. This is may not work like you expect, it is particularly dangerous when casting C++ objects, and it won't work if you switch to a new pointer representation such as CObjects. If you need to cast a pointer or change its value, consider writing some helper functions instead. For example:>>> a '_88671008_p_Circle' >>> b '_605f0c08_p_Square' >>>
If you need to type-cast a lot of objects, it may indicate a serious weakness in your design. Also, if working with C++, you should always try to use the new C++ style casts. For example, in the above code, the C-style cast may return a bogus result whereas as the C++-style cast will return None if the conversion can't be performed.%inline %{ /* C-style cast */ Bar *FooToBar(Foo *f) { return (Bar *) f; } /* C++-style cast */ Foo *BarToFoo(Bar *b) { return dynamic_cast<Foo*>(b); } Foo *IncrFoo(Foo *f, int i) { return f+i; } %}
gets mapped into the following collection of accessor functions:struct Vector { double x,y,z; };
These functions are then used to access structure data from Python as follows:struct Vector *new_Vector(); void delete_Vector(Vector *v); double Vector_x_get(Vector *obj) void Vector_x_set(Vector *obj, double x) double Vector_y_get(Vector *obj) void Vector_y_set(Vector *obj, double y) double Vector_z_get(Vector *obj) void Vector_z_set(Vector *obj, double z)
>>> v = new_Vector() >>> Vector_x_get(v) 3.5 >>> Vector_x_set(v,7.8) # Change x component >>> print Vector_x_get(v), Vector_y_get(v), Vector_z_get(v) 7.8 -4.5 0.0 >>>
Similar access is provided for unions and the data members of C++ classes.
const members of a structure are read-only. Data members can also be forced to be read-only using the %readonly directive. For example:
struct Foo { ... %readonly int x; /* Read-only members */ char *name; %readwrite ... };
When char * members of a structure are wrapped, the contents are assumed to be dynamically allocated using malloc or new (depending on whether or not SWIG is run with the -c++ option). When the structure member is set, the old contents will be released and a new value created. If this is not the behavior you want, you will have to use a typemap (described shortly).
Array members are normally wrapped as read-only. For example,
produces a single accessor function like this:struct Foo { int x[50]; };
If you want to set an array member, you will need to supply a "memberin" typemap described later in this chapter. As a special case, SWIG does generate code to set array members of type char (allowing you to store a Python string in the structure).int *Foo_x_get(Foo *self) { return self->x; };
When structure members are wrapped, they are handled as pointers. For example,
generates accessor functions such as this:struct Foo { ... }; struct Bar { Foo f; };
Foo *Bar_f_get(Bar *b) { return &b->f; } void Bar_f_set(Bar *b, Foo *val) { b->f = *val; }
class List { public: List(); ~List(); int search(char *item); void insert(char *item); void remove(char *item); char *get(int n); int length; static void print(List *l); };
When wrapped by SWIG, the following functions are created :
In Python, these functions are used as follows:List *new_List(); void delete_List(List *l); int List_search(List *l, char *item); void List_insert(List *l, char *item); void List_remove(List *l, char *item); char *List_get(List *l, int n); int List_length_get(List *l); void List_length_set(List *l, int n); void List_print(List *l);
At this low level, C++ objects are really just typed pointers. Member functions are accessed by calling a C-like wrapper with an instance pointer as the first argument. Although this interface is fairly primitive, it provides direct access to C++ objects. A higher level interface known as shadow classes can be built using these low-level accessors. This is described shortly.>>> l = new_List() >>> List_insert(l,"Ale") >>> List_insert(l,"Stout") >>> List_insert(l,"Lager") >>> List_print(l) Lager Stout Ale >>> print List_length_get(l) 3 >>> print l _80085608_p_List >>>
and a functionclass Foo { ... }; class Bar : public Foo { ... };
then the function spam() accepts Foo * or a pointer to any class derived from Foo. If necesssary, the type-checker also adjusts the value of the pointer (as is necessary when multiple inheritance is used).void spam(Foo *f);
Now, in Python, the methods are accessed as follows:/* Forward renaming declarations */ %rename(foo_i) foo(int); %rename(foo_d) foo(double); ... void foo(int); // Becomes 'foo_i' void foo(char *c); // Stays 'foo' (not renamed) class Spam { public: void foo(int); // Becomes 'foo_i' void foo(double); // Becomes 'foo_d' ... };
Please refer to the "SWIG Basics" chapter for more information.>>> import example >>> example.foo_i(3) >>> s = example.new_Spam() >>> Spam_foo_i(s,3) >>> Spam_foo_d(s,3.14)
Now, in Python, you can do this:%rename(add_complex) operator+(Complex &, Complex &); ... Complex operator+(Complex &, Complex &);
More details about wrapping C++ operators into Python operators is discussed a little later.>>> a = example.new_Complex(2,3) >>> b = example.new_Complex(4,-1) >>> c = example.add_complex(a,b)
or perhapsvoid add(int x, int y, int *result) { *result = x + y; }
The easiest way to handle these situations is to use the typemaps.i file. For example:int sub(int *x, int *y) { return *x+*y; }
In Python, this allows you to pass simple values. For example:%module example %include "typemaps.i" void add(int, int, int *OUTPUT); int sub(int *INPUT, int *INPUT);
Notice how the INPUT parameters allow integer values to be passed instead of pointers and how the OUTPUT parameter creates a return result.>>> a = add(3,4) >>> print a 7 >>> b = sub(7,4) >>> print b 3 >>>
If you don't want to use the names INPUT or OUTPUT, use the %apply directive. For example:
%module example %include "typemaps.i" %apply int *OUTPUT { int *result }; %apply int *INPUT { int *x, int *y}; void add(int x, int y, int *result); int sub(int *x, int *y);
If a function mutates one of its parameters like this,
you can use INOUT like this:void negate(int *x) { *x = -(*x); }
In Python, a mutated parameter shows up as a return value. For example:%include "typemaps.i" ... void negate(int *INOUT);
Note: Since most primitive Python objects are immutable, it is not possible to perform in-place modification of a Python object passed as a parameter.>>> a = negate(3) >>> print a -3 >>>
The most common use of these special typemap rules is to handle functions that return more than one value. For example, sometimes a function returns a result as well as a special error code:
To wrap such a function, simply use the OUTPUT rule above. For example:/* send message, return number of bytes sent, along with success code */ int send_message(char *text, int len, int *success);
When used in Python, the function will return multiple values.%module example %include "typemaps.i" %apply int *OUTPUT { int *success }; ... int send_message(char *text, int *success);
Another common use of multiple return values are in query functions. For example:bytes, success = send_message("Hello World") if not success: print "Whoa!" else: print "Sent", bytes
To wrap this, you might use the following:void get_dimensions(Matrix *m, int *rows, int *columns);
Now, in Python:%module example %include "typemaps.i" %apply int *OUTPUT { int *rows, int *columns }; ... void get_dimensions(Matrix *m, int *rows, *columns);
>>> r,c = get_dimensions(m)
class RangeError {}; // Used for an exception class DoubleArray { private: int n; double *ptr; public: // Create a new array of fixed size DoubleArray(int size) { ptr = new double[size]; n = size; } // Destroy an array ~DoubleArray() { delete ptr; } // Return the length of the array int length() { return n; } // Get an item from the array and perform bounds checking. double getitem(int i) { if ((i >= 0) && (i < n)) return ptr[i]; else throw RangeError(); } // Set an item in the array and perform bounds checking. void setitem(int i, double val) { if ((i >= 0) && (i < n)) ptr[i] = val; else { throw RangeError(); } } };
Since several methods in this class can throw an exception for an out-of-bounds access, you might want to catch this in the Python extension by writing the following in an interface file:
The exception handling code is inserted directly into generated wrapper functions. The $action variable is replaced with the C/C++ code being executed by the wrapper. When an exception handler is defined, errors can be caught and used to gracefully raise a Python exception instead of forcing the entire program to terminate with an uncaught error.%exception { try { $action } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } } class DoubleArray { ... };
As shown, the exception handling code will be added to every wrapper function. Since this is somewhat inefficient. You might consider refining the exception handler to only apply to specific methods like this:
In this case, the exception handler is only attached to methods and functions named getitem and setitem.%exception getitem { try { $action } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } } %exception setitem { try { $action } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } }
If you had a lot of different methods, you can avoid extra typing by using a macro. For example:
Since SWIG's exception handling is user-definable, you are not limited to C++ exception handling. See the chapter on "Exception Handling" for more examples.%define RANGE_ERROR { try { $action } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } } %enddef %exception getitem RANGE_ERROR; %exception setitem RANGE_ERROR;
When raising a Python exception from C, use the PyErr_SetString() function as shown above. The following exception types can be used as the first argument.
These exceptions are actually organized into an hierarchy as shown below. Consult the Python Essential Reference for more details (shameless plug):PyExc_ArithmeticError PyExc_AssertionError PyExc_AttributeError PyExc_EnvironmentError PyExc_EOFError PyExc_Exception PyExc_FloatingPointError PyExc_ImportError PyExc_IndexError PyExc_IOError PyExc_KeyError PyExc_KeyboardInterrupt PyExc_LookupError PyExc_MemoryError PyExc_NameError PyExc_NotImplementedError PyExc_OSError PyExc_OverflowError PyExc_RuntimeError PyExc_StandardError PyExc_SyntaxError PyExc_SystemError PyExc_TypeError PyExc_UnicodeError PyExc_ValueError PyExc_ZeroDivisionError
PyExc_Exception PyExc_SystemExit PyExc_StandardError PyExc_ArithmeticError PyExc_FloatingPointError PyExc_OverflowError PyExc_ZeroDivisionError PyExc_AssertionError PyExc_AttributeError PyExc_EnvironmentError PyExc_IOError PyExc_OSError PyExc_EOFError PyExc_ImportError PyExc_KeyboardInterrupt PyExc_LookupError PyExc_IndexError PyExc_KeyError PyExc_MemoryError PyExc_NameError PyExc_RuntimeError PyExc_NotImplementedError PyExc_SyntaxError PyExc_SystemError PyExc_TypeError PyExc_ValueError PyExc_UnicodeError
Compatibility note: In SWIG1.1, exceptions were defined using the older %except directive:
This is still supported, but it is deprecated. The newer %exception directive provides the same functionality, but it has additional capabilities that make it more powerful.%except(python) { try { $action } catch (RangeError) { PyErr_SetString(PyExc_IndexError,"index out-of-bounds"); return NULL; } }
Before proceeding, it should be stressed that typemaps are not a required part of using SWIG---the default wrapping behavior is enough in most cases. Typemaps are only used if you want to change some aspect of the primitive C-Python interface.
%module example %typemap(in) int { $1 = (int) PyLong_AsLong($input); printf("Received an integer : %d\n",$1); } extern int fact(int n);
Typemaps are always associated with some specific aspect of code generation. In this case, the "in" method refers to the conversion of input arguments to C/C++. The datatype int is the datatype to which the typemap will be applied. The supplied C code is used to convert values. In this code a number of special variable prefaced by a $ are used. The $1 variable is placeholder for a local variable of type int. The $input variable is the input object of type PyObject *.
When this example is compiled into a Python module, it operates as follows:
>>> from example import * >>> fact(6) Received an integer : 6 720
In this example, the typemap is applied to all occurrences of the int datatype. You can refine this by supplying an optional parameter name. For example:
In this case, the typemap code is only attached to arguments that exactly match int n.%module example %typemap(in) int n { $1 = (int) PyLong_AsLong($input); printf("n = %d\n",$1); } extern int fact(int n);
The application of a typemap to specific datatypes and argument names involves more than simple text-matching--typemaps are fully integrated into the SWIG type-system. When you define a typemap for int, that typemap applies to int and qualified variations such as const int. In addition, the typemap system follows typedef declarations. For example:
However, the matching of typedef only occurs in one direction. If you defined a typemap for Integer, it is not applied to arguments of type int.%typemap(in) int n { $1 = (int) PyLong_AsLong($input); printf("n = %d\n",$1); } typedef int Integer; extern int fact(Integer n); // Above typemap is applied
Typemaps can also be defined for groups of consecutive arguments. For example:
When a multi-argument typemap is defined, the arguments are always handled as a single Python object. This allows the function to be used like this (notice how the length parameter is ommitted):%typemap(in) (char *str, int len) { $1 = PyString_AsString($input); $2 = PyString_Size($input); }; int count(char c, char *str, int len);
>>> example.count('e','Hello World') 1 >>>
The following list details all of the typemap methods that can be used by the Python module:%typemap(out) int { $result = PyInt_FromLong((long) $1); }
%typemap(in)
Converts Python objects to input function arguments%typemap(out)
Converts return value of a C function to a Python object%typemap(varin)
Assigns a C global variable from a Python object%typemap(varout)
Returns a C global variable as a Python object%typemap(freearg)
Cleans up a function argument (if necessary)%typemap(argout)
Output argument processing%typemap(ret)
Cleanup of function return values%typemap(consttab)
Creation of Python constants (constant table)%typemap(constcode)
Creation of Python constants (init function)%typemap(memberin)
Setting of structure/class member data%typemap(globalin)
Setting of C global variables%typemap(check)
Checks function input values.%typemap(default)
Set a default value for an argument (making it optional).%typemap(ignore)
Ignore an argument, but initialize its value.%typemap(arginit)
Initialize an argument to a value before any conversions occur.Examples of these methods will appear shortly.
$1
A C local variable corresponding to the actual type specified in the %typemap directive. For input values, this is a C local variable that's supposed to hold an argument value. For output values, this is the raw result that's supposed to be returned to Python.
$input
A PyObject * holding a raw Python object with an argument or variable value.
$result
A PyObject * that holds the result to be returned to Python.
$1_name
The parameter name that was matched.
$1_type
The actual C datatype matched by the typemap.
$1_ltype
An assignable version of the datatype matched by the typemap (a type that can appear on the left-hand-side of a C assignment operation). This type is stripped of qualifiers and may be an altered version of $1_type. All arguments and local variables in wrapper functions are declared using this type so that their values can be properly assigned.$symname
The Python name of the wrapper function being created.
Python Integer Functions
Python Floating Point FunctionsPyObject *PyInt_FromLong(long l); long PyInt_AsLong(PyObject *); int PyInt_Check(PyObject *);
Python String FunctionsPyObject *PyFloat_FromDouble(double); double PyFloat_AsDouble(PyObject *); int PyFloat_Check(PyObject *);
Python List FunctionsPyObject *PyString_FromString(char *); PyObject *PyString_FromStringAndSize(char *, lint len); int PyString_Size(PyObject *); char *PyString_AsString(PyObject *); int PyString_Check(PyObject *);
Python Tuple FunctionsPyObject *PyList_New(int size); int PyList_Size(PyObject *list); PyObject *PyList_GetItem(PyObject *list, int i); int PyList_SetItem(PyObject *list, int i, PyObject *item); int PyList_Insert(PyObject *list, int i, PyObject *item); int PyList_Append(PyObject *list, PyObject *item); PyObject *PyList_GetSlice(PyObject *list, int i, int j); int PyList_SetSlice(PyObject *list, int i, int , PyObject *list2); int PyList_Sort(PyObject *list); int PyList_Reverse(PyObject *list); PyObject *PyList_AsTuple(PyObject *list); int PyList_Check(PyObject *);
Python Dictionary FunctionsPyObject *PyTuple_New(int size); int PyTuple_Size(PyObject *); PyObject *PyTuple_GetItem(PyObject *, int i); int PyTuple_SetItem(PyObject *, int i, pyObject *item); PyObject *PyTuple_GetSlice(PyObject *t, int i, int j); int PyTuple_Check(PyObject *);
Python File Conversion Functionswrite me
Abstract Object InterfacePyObject *PyFile_FromFile(FILE *f); FILE *PyFile_AsFile(PyObject *); int PyFile_Check(PyObject *);
write me
When this module is compiled, the wrapped C function now operates as follows :%module argv // This tells SWIG to treat char ** as a special case %typemap(in) char ** { /* Check if is a list */ if (PyList_Check($input)) { int size = PyList_Size($input); int i = 0; $1 = (char **) malloc((size+1)*sizeof(char *)); for (i = 0; i < size; i++) { PyObject *o = PyList_GetItem($input,i); if (PyString_Check(o)) $1[i] = PyString_AsString(PyList_GetItem($input,i)); else { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); return NULL; } } $1[i] = 0; } else { PyErr_SetString(PyExc_TypeError,"not a list"); return NULL; } } // This cleans up the char ** array we malloc'd before the function call %typemap(freearg) char ** { free((char *) $1); } // Now a test function %inline %{ int print_args(char **argv) { int i = 0; while (argv[i]) { printf("argv[%d] = %s\n", i,argv[i]); i++; } return i; } %}
In the example, two different typemaps are used. The "in" typemap is used to receive an input argument and convert it to a C array. Since dynamic memory allocation is used to allocate memory for the array, the "freearg" typemap is used to later release this memory after the execution of the C function.>>> from argv import * >>> print_args(["Dave","Mike","Mary","Jane","John"]) argv[0] = Dave argv[1] = Mike argv[2] = Mary argv[3] = Jane argv[4] = John 5
In the previous example, a typemap was written to pass a Python list as the char **argv. This allows the function to be used from Python as follows:int foo(int argc, char **argv);
Although this works, it's a little awkward to specify the argument count. To fix this, a multi-argument typemap can be defined. This is not very difficult--you only have to make slight modifications to the previous example:>>> foo(4, ["foo","bar","spam","1"])
When writing a multiple-argument typemap, each of the types is referenced by a variable such as $1 or $2. The typemap code simply fills in the appropriate values from the supplied Python object.%typemap(in) (int argc, char **argv) { /* Check if is a list */ if (PyList_Check($input)) { int i; $1 = PyList_Size($input); $2 = (char **) malloc((size+1)*sizeof(char *)); for (i = 0; i < $1; i++) { PyObject *o = PyList_GetItem($input,i); if (PyString_Check(o)) $2[i] = PyString_AsString(PyList_GetItem($input,i)); else { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($2); return NULL; } } $2[i] = 0; } else { PyErr_SetString(PyExc_TypeError,"not a list"); return NULL; } } %typemap(freearg) (int argc, char **argv) { free((char *) $2); }
With the above typemap in place, you will find it no longer necessary to supply the argument count. This is automatically set by the typemap code. For example:
>>> foo(["foo","bar","spam","1"])
A typemap can be used to handle this case as follows :/* Returns a status value and two values in out1 and out2 */ int spam(double a, double b, double *out1, double *out2) { ... Do a bunch of stuff ... *out1 = result1; *out2 = result2; return status; };
The typemap works as follows. First, a check is made to see if any previous result exists. If so, it is turned into a tuple and the new output value is concatenated to it. Otherwise, the result is returned normally. For the sample function spam(), there are three output values--meaning that the function will return a 3-tuple of the results.%module outarg // This tells SWIG to treat an double * argument with name 'OutValue' as // an output value. We'll append the value to the current result which // is guaranteed to be a List object by SWIG. %typemap(argout) double *OutValue { PyObject *o, *o2, *o3; o = PyFloat_FromDouble(*$1); if ((!$result) || ($result == Py_None)) { $result = o; } else { if (!PyTuple_Check($result)) { PyObject *o2 = $result; $result = PyTuple_New(1); PyTuple_SetItem(target,0,o2); } o3 = PyTuple_New(1); PyTuple_SetItem(o3,0,o); o2 = $result; $result = PySequence_Concat(o2,o3); Py_DECREF(o2); Py_DECREF(o3); } } int spam(double a, double b, double *OutValue, double *OutValue);
As written, the function must accept 4 arguments as input values, last two being pointers to doubles. If these arguments are only used to hold output values (and have no meaningful input value), an additional typemap can be written. For example:
The ignore typemap forces the input value to be ignored. However, since the argument still has to be set to some meaningful value before calling C, it is set to point to a local variable temp. When the function stores its output value, it will simply be placed in this local variable. As a result, the function can now be used as follows:%typemap(ignore) double *OutValue(double temp) { $1 = &temp; }
>>> a = spam(4,5) >>> print a (0, 2.45, 5.0) >>> x,y,z = spam(4,5) >>>
extern void set_direction(double a[4]); // Set direction vector
This too, can be handled used typemaps as follows :
This allows our set_direction function to be called from Python as follows :// Grab a 4 element array as a Python 4-tuple %typemap(in) double[4](double temp[4]) { // temp[4] becomes a local variable int i; if (PyTuple_Check($input)) { if (!PyArg_ParseTuple($input,"dddd",temp,temp+1,temp+2,temp+3)) { PyErr_SetString(PyExc_TypeError,"tuple must have 4 elements"); return NULL; } $1 = &temp[0]; } else { PyErr_SetString(PyExc_TypeError,"expected a tuple."); return NULL; } }
Since our mapping copies the contents of a Python tuple into a C array, such an approach would not be recommended for huge arrays, but for small structures, this approach works fine.>>> set_direction((0.5,0.0,1.0,-0.25))
In this case, the variable $1_dim0 is expanded to match the array dimensions actually used in the C code. This allows the typemap to be applied to types such as:// Map a Python sequence into any sized C double array %typemap(in) double[ANY](double temp[$1_dim0]) { int i; if (!PySequence_Check($input)) { PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); return NULL; } if (PyObject_Length($input) != $1_dim0) { PyErr_SetString(PyExc_ValueError,"Expecting a sequence with $1_dim0 elements"); return NULL; } for (i =0; i < $1_dim0; i++) { PyObject *o = PySequence_GetItem($input,i); if (!PyFloat_Check(o)) { PyErr_SetString(PyExc_ValueError,"Expecting a sequence of floats"); return NULL; } temp[i] = PyFloat_AsDouble(o); } $1 = &temp[0]; }
Since the above typemap code gets inserted into every wrapper function where used, it might make sense to use a helper function instead. This will greatly reduce the amount of wrapper code. For example:void foo(double x[10]); void bar(double a[4], double b[8]);
%{ static int convert_darray(PyObject *input, double *ptr, int size) { int i; if (!PySequence_Check(input)) { PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); return 0; } if (PyObject_Length(input) != size) { PyErr_SetString(PyExc_ValueError,"Sequence size mismatch"); return 0; } for (i =0; i < size; i++) { PyObject *o = PySequence_GetItem(input,i); if (!PyFloat_Check(o)) { PyErr_SetString(PyExc_ValueError,"Expecting a sequence of floats"); return 0; } ptr[i] = PyFloat_AsDouble(o); } return 1; } %} %typemap(in) double [ANY](double temp[$1_dim0]) { if (!convert_darray($input,temp,$1_dim0))) { return NULL; } $1 = &temp[0]; }
By default, SWIG doesn't know how to the handle the values structure member it's an array, not a pointer. In this case, SWIG makes the array member read-only. Reading will simply return a pointer to the first item in the array. To make the member writable, a "memberin" typemap can be used.#define SIZE 8 typedef struct { int values[SIZE]; ... } Foo;
Whenever a int [SIZE] member is encountered in a structure or class, this typemap provides a safe mechanism for setting its value.%typemap(memberin) int [SIZE] { int i; for (i = 0; i < SIZE; i++) { $1[i] = $input[i]; } }
As in the previous example, the typemap can be generalized for any dimension. For example:
When setting structure members, the input object is always assumed to be a C array of values that have already been converted from the target language. Because of this, the memberin typemap is almost always combined with the use of an "in" typemap. For example, the "in" typemap in the previous section would be used to convert an int[] array to C whereas the "memberin" typemap would be used to copy the converted array into a C data structure.%typemap(memberin) int [ANY] { int i; for (i = 0; i < $1_dim0; i++) { $1[i] = $input[i]; } }
int SWIG_ConvertPtr(PyObject *obj, void **ptr, swig_type_info *ty, int flags)
Converts a Python object obj to a C pointer. The result of the conversion is placed into the pointer located at ptr. ty is a SWIG type descriptor structure. flags is used to handle error checking and other aspects of conversion. If set, the function converts type-errors into a Python TypeError exception. If set to zero, no Python exception is raised. Returns 0 on success and -1 on error.
PyObject *Swig_NewPointerObj(void *ptr, swig_type_info *ty, int own)
Creates a new Python pointer object. ptr is the pointer to convert, ty is the SWIG type descriptor structure that describes the type, and own is a flag that indicates whether or not Python should take ownership of the pointer.Both of these functions require the use of a special SWIG type-descriptor structure. This structure contains information about the mangled name of the datatype, type-equivalence information, as well as information about converting pointer values under C++ inheritance. For a type of Foo *, the type descriptor structure is usually accessed as follows:
In a typemap, the type descriptor should always be accessed using the special typemap variable $1_descriptor. For example:Foo *f; if (SWIG_ConvertPtr($input, (void **) &f, SWIGTYPE_p_Foo, 1) == -1) return NULL; PyObject *obj; obj = SWIG_NewPointerObj(f, SWIGTYPE_p_Foo, 0);
Although the pointer handling functions are primarily intended for manipulating low-level pointers, both functions are fully aware of Python shadow classes (described shortly). Specifically, SWIG_ConvertPtr() will retrieve a pointer from any object that has a this attribute. In addition, SWIG_NewPointerObj() can automatically generate a shadow class object (if applicable).%typemap(in) Foo * { if ((SWIG_ConvertPtr($input,(void **) &$1, $1_descriptor,1)) == -1) return NULL; }
This function can be added to a SWIG module using the following declaration :PyObject *spam_system(PyObject *self, PyObject *args) { char *command; int sts; if (!PyArg_ParseTuple(args,"s",&command)) return NULL; sts = system(command); return Py_BuildValue("i",sts); }
Alternatively, you can use the full function declaration like this%native(system) spam_system; // Create a command called `system'
%native(system) PyObject *spam_system(PyObject *self, PyObject *args);
or
%native(system) extern PyObject *spam_system(PyObject *self, PyObject *args);
class List: def __init__(self): self.this = new_List() def __del__(self): delete_List(self.this) def search(self,item): return List_search(self.this,item) def insert(self,item): List_insert(self.this,item) def remove(self,item): List_remove(self.this,item) def get(self,n): return List_get(self.this,n) def __getattr__(self,name): if name == "length" : return List_length_get(self.this)) else : return self.__dict__[name] def __setattr__(self,name,value): if name == "length": List_length_set(self.this,value) else : self.__dict__[name] = value
In the shadow class, a reference to the underlying C++ object is kept in the .this attribute. Methods are then written so that they pass the .this attribute along with the other arguments to the low-level accessor function created by SWIG. This, in turn, allows the class to be used like this:
>>> l = List() >>> l.insert("Ale") >>> l.insert("Stout") >>> l.insert("Lager") >>> List_print(l.this) Lager Stout Ale >>> l.length 3
Clearly, this is a much nicer interface than before--and it only required a small amount of Python coding.
Shadow classes allow C++ objects to be easily wrapped by a real Python class. This means that all of the normal features such as inheritance work like you would expect. The fact that such classes are written in Python also simplifies coding since it is much easier to write a class interface in Python than it is in C. Such classes are also much easier to modify since changes can be made without having to recompile any of the low-level C extension code. The main downside to this approach is worse performance--a concern for some users.
This generates the usual wrapper file along with an extra file module.py that contains the Python shadow-class code. The name of this file is the same as specified by the %module directive.swig -python -shadow interface.i
Since the shadow class code needs to be placed in a different module than the low-level C wrappers, the primitive interface is placed into a Python extension module named modulec (a 'c' is appended to the module name). When a user imports the module, the module.py is loaded. This file, in turn, imports the low-level C wrapper module to gain access to the accessor functions. For example, in the list example, the shadow file might look roughly like this:
The choice of appending a 'c' to the module name is somewhat non-standard and may cause a module name conflict in certain cases. To fix this, you can run SWIG with the -interface option to change the name of the C module file. For example, this places the low-level C interface into a module named _example:# example import examplec class List: def __init__(self): self.this = examplec.new_List() def __del__(self): examplec.delete_List(self.this) def search(self,item): return examplec.List_search(self.this,item) def insert(self,item): examplec.List_insert(self.this,item) def remove(self,item): examplec.List_remove(self.this,item) def get(self,n): return examplec.List_get(self.this,n) def __getattr__(self,name): if name == "length" : return examplec.List_length_get(self.this)) else : return self.__dict__[name] def __setattr__(self,name,value): if name == "length": examplec.List_length_set(self.this,value) else : self.__dict__[name] = value
When shadow classes are used, most users don't notice the existence of the low-level C accessors. In fact, there is very little reason to use the low-level functions directly as shadow classes provide all of the needed access.$ swig -python -shadow -c++ -interface _example example.i
might be compiled as follows :%module example ... a bunch of declarations ...
Notice the naming of `examplecmodule.so' as opposed to `examplemodule.so' that would have been created without shadow classes.% swig -python -shadow example.i % gcc -c example.c example_wrap.c -I/usr/local/include/python1.4 \ -I/usr/local/lib/python1.4/config -DHAVE_CONFIG_H % ld -shared example.o example_wrap.o -o examplecmodule.so
You can also observe this behavior of the type checker with a little experimentation. For example:class List: def __init__(self): self.this = new_List() def __del__(self): delete_List(self) # Notice how self is passed instead of def search(self,item): # self.this return List_search(self,item) def insert(self,item): List_insert(self,item) def remove(self,item): List_remove(self,item) def get(self,n): return List_get(self,n) def __getattr__(self,name): if name == "length" : return List_length_get(self)) else : return self.__dict__[name] def __setattr__(self,name,value): if name == "length": List_length_set(self,value) else : self.__dict__[name] = value
Further details of type-checking and shadow classes will be described later. Stay tuned.>>> import example >>> a = example.new_List() >>> a '_90651008_p_List' >>> example.List_insert(a,"Ale") >>> class Blah: pass ... >>> b = Blah() >>> b.this = a >>> example.List_insert(b,"Lager") >>>
%module pde struct Grid2d { Grid2d(int ni, int nj); ~Grid2d(); double **data; int xpoints; int ypoints; };
The SWIG generated class for this structure looks like the following:
# This file was created automatically by SWIG. import pdec class Grid2dPtr : def __init__(self,this): self.this = this self.thisown = 0 def __del__(self): if self.thisown == 1 : pdec.delete_Grid2d(self.this) def __setattr__(self,name,value): if name == "data" : pdec.Grid2d_data_set(self.this,value) return if name == "xpoints" : pdec.Grid2d_xpoints_set(self.this,value) return if name == "ypoints" : pdec.Grid2d_ypoints_set(self.this,value) return self.__dict__[name] = value def __getattr__(self,name): if name == "data" : return pdec.Grid2d_data_get(self.this) if name == "xpoints" : return pdec.Grid2d_xpoints_get(self.this) if name == "ypoints" : return pdec.Grid2d_ypoints_get(self.this) return self.__dict__[name] def __repr__(self): return "<C Grid2d instance>" class Grid2d(Grid2dPtr): def __init__(self,arg0,arg1) : self.this = pdec.new_Grid2d(arg0,arg1) self.thisown = 1
The Grid2d class, on the other hand, is used when you want to create a new Grid2d object from Python. In reality, it inherits all of the attributes of a Grid2dPtr, except that its constructor calls the corresponding C++ constructor to create a new object. Thus, in Python, this would look something like the following :>>> gptr = create_grid2d() # Returns a Grid2d from somewhere >>> g = Grid2dPtr(gptr) # Turn it into a Python class >>> g.xpoints 50 >>>
This two class model is a tradeoff. In order to support C/C++ properly, it is necessary to be able to create Python objects from both pre-existing C++ objects and to create entirely new C++ objects in Python. While this might be accomplished using a single class, it would complicate the handling of constructors considerably. The two class model, on the other hand, works, is consistent, and is relatively easy to use. In practice, you probably won't even be aware that there are two classes working behind the scenes.>>> g = Grid2d(50,50) # Create a new Grid2d >>> g.xpoints 50 >>>
>>> g = Grid2d(50,50) >>> print g.this _1008fe8_Grid2d_p >>>
Direct manipulation of the "this" pointer is generally discouraged. In fact forget that you read this.
Ownership of an object can be changed as necessary by changing the value of thisown. When set, Python will call the C/C++ destructor when the object is deleted. If it is zero, Python will never call the C/C++ destructor.
By default, the function addv will operate on Vector pointers, not Python classes. However, the SWIG Python module is smart enough to know that Vector has been wrapped into a Python class so it will create the following replacement for the addv() function.%module vector struct Vector { Vector(); ~Vector(); double x,y,z; }; Vector addv(Vector a, Vector b);
Function arguments are modified to use the "this" pointer of a Python Vector object. The result is a pointer to the result which has been allocated by malloc or new (this behavior is described in the chapter on SWIG basics), so we simply create a new VectorPtr with the return value. Since the result involved an implicit malloc, we set the ownership to 1 indicating that the result is to be owned by Python and that it should be deleted when the Python object is deleted. As a result, operations like this are perfectly legal and result in no memory leaks :def addv(a,b): result = VectorPtr(vectorc.addv(a.this,b.this)) result.thisown = 1 return result
Substitution of complex datatypes occurs for all functions and member functions involving structure or class definitions. It is rarely necessary to use the low-level C interface when working with shadow classes.>>> v = add(add(add(add(a,b),c),d),e)
%module particle typedef struct { Vector(); double x,y,z; } Vector; typedef struct { Particle(); ~Particle(); Vector r; Vector v; Vector f; int type; } Particle;
In this case you will be able to access members as follows :
Nesting of objects is implemented using Python's __setattr__ and __getattr__ functions. In this case, they would look like this :>>> p = Particle() >>> p.r.x = 0.0 >>> p.r.y = -1.5 >>> p.r.z = 2.0 >>> p.v = addv(v1,v2) >>> ...
The attributes of any given object are only converted into a Python object when referenced. This approach is more memory efficient, faster if you have a large collection of objects that aren't examined very often, and works with recursive structure definitions such as :class ParticlePtr: ... def __getattr__(self,name): if name == "r": return particlec.VectorPtr(Particle_r_get(self.this)) elif name == "v": return particlec.VectorPtr(Particle_v_get(self.this)) ... def __setattr__(self,name,value): if name == "r": particlec.Particle_r_set(self.this,value.this) elif name == "v": particlec.Particle_v_set(self.this,value.this) ...
struct Node { char *name; struct Node *next; };
Nested structures such as the following are also supported by SWIG. These types of structures tend to arise frequently in database and information processing applications.
Access is provided in an entirely natural manner,typedef struct { unsigned int dataType; union { int intval; double doubleval; char *charval; void *ptrvalue; long longval; struct { int i; double f; void *v; char name[32]; } v; } u; } ValueStruct;
To support the embedded structure definitions, SWIG has to extract the internal structure definitions and use them to create new Python classes. In this example, the following shadow classes are created :>>> v = new_ValueStruct() # Create a ValueStruct somehow >>> v.dataType 1 >>> v.u.intval 45 >>> v.u.longval 45 >>> v.u.v.v = _0_void_p >>>
# Class corresponding to union u member class ValueStruct_u : ... # Class corresponding to struct v member of union u class ValueStruct_u_v : ...
The names of the new classes are formed by appending the member names of each embedded structure.
When the value is returned to Python, we want Python to assume ownership. The brute force way to do this is to simply change the value of thisown. For example :Vector *cross_product(Vector *v1, Vector *v2) { Vector *result = new Vector(); result = ... compute cross product ... return result; }
Unfortunately, this is ugly and it doesn't work if we use the result as a temporary value :>>> v = cross_product(a,b) >>> v.thisown = 1 # Now Python owns it
w = vector_add(cross_product(a,b),c) # Results in a memory leak
However, you can provide a hint to SWIG when working with such a function as shown :
The %new directive only provides a hint that the function is returning a new object. The Python module will assign proper ownership of the object when this is used.// C Function returning a new object %new Vector *cross_product(Vector *v1, Vector *v2);
There are a number of ways to optimize programs that use shadow classes. Consider the following two code fragments involving the Particle data structure in a previous example :
The first calculation simply works with each Particle structure directly. Unfortunately, it performs alot of dereferencing of objects. If the calculation is restructured to use temporary variables as shown in force2, it will run significantly faster--in fact, on my machine, the second code fragment runs more than twice as fast as the first one.def force1(p1,p2): dx = p2.r.x - p1.r.x dy = p2.r.y - p1.r.y dz = p2.r.z - p1.r.z r2 = dx*dx + dy*dy + dz*dz f = 1.0/(r2*math.sqrt(r2)) p1.f.x = p1.f.x + f*dx p2.f.x = p2.f.x - f*dx p1.f.y = p1.f.y + f*dy p2.f.y = p2.f.y - f*dy p1.f.z = p1.f.z + f*dz p2.f.z = p2.f.z - f*dz def force2(p1,p2): r1 = p1.r r2 = p2.r dx = r2.x - r1.x dy = r2.y - r1.y dz = r2.z - r1.z r2 = dx*dx + dy*dy + dz*dz f = 1.0/(r2*math.sqrt(r2)) f1 = p1.f f2 = p2.f f1.x = f1.x + f*dx f2.x = f2.x - f*dx f1.y = f1.y + f*dy f2.y = f2.y - f*dy f1.z = f1.z + f*dz f2.z = f2.z - f*dz
If performance is even more critical you can use the low-level C interface which eliminates all of the overhead of going through Python's class mechanism (at the expense of coding simplicity). When Python shadow classes are used, the low level C interface can still be used by importing the `modulec' module where `module' is the name of the module you used in the SWIG interface file.