You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2132 lines
68 KiB
2132 lines
68 KiB
<html>
|
|
|
|
<head>
|
|
<meta HTTP-ETQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
|
<title>Writing Python Extensions in C++</title>
|
|
<style>
|
|
H1, H2, H3, H4 {color: #000099;
|
|
background-color: lightskyblue}
|
|
h3 {position: relative; left: 20px}
|
|
|
|
p {position: relative; left: 20px; margin-right: 20px}
|
|
pre {color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px;
|
|
border-style: solid; border-color: black; border-width: thin}
|
|
kbd {color: #990000}
|
|
p cite, ol cite, ul cite {font-family: monospace; font-style: normal; font-size: normal}
|
|
li var, pre var, p var, kbd var {color: #009900; font-style: italic}
|
|
li samp, pre samp, p samp, kbd samp {color: #009900; font-weight: bold}
|
|
li p {position: relative; left: 0}
|
|
table { position: relative; left: 20px; border: solid #888888 1px; background-color: #eeeeee}
|
|
table th {border: solid #888888 1px; background-color: #88dd88; color: black}
|
|
table td {border: solid #888888 1px}
|
|
table td.code {border: solid #888888 1px;font-family: monospace; font-style: normal; font-size: normal}
|
|
p.param {background-color: #eeeeee; border-top: lightskyblue solid 4}
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body bgcolor="#FFFFFF">
|
|
|
|
<h1 ALIGN="center">Writing Python Extensions in C++</h1>
|
|
|
|
<p ALIGN="CENTER">Barry Scott<br>
|
|
Reading, Berkshire, England<br>
|
|
<a href="mailto:barry@barrys-emacs.org">barry@barrys-emacs.org</a><br>
|
|
</p>
|
|
|
|
<p ALIGN="CENTER">Paul F. Dubois, <a href="mailto:dubois1@llnl.gov">dubois1@llnl.gov</a><br>
|
|
Lawrence Livermore National Laboratory<br>
|
|
Livermore, California, U.S.A.</p>
|
|
|
|
|
|
<p>PyCXX is designed to make it easier to extend Python with C++</p>
|
|
|
|
|
|
<p>PyCXX is a set of C++ facilities to make it easier to write Python extensions.
|
|
The chief way in which PyCXX makes it easier to write Python extensions is that it greatly
|
|
increases the probability that your program will not make a reference-counting error and
|
|
will not have to continually check error returns from the Python C API. PyCXX
|
|
integrates Python with C++ in these ways: </p>
|
|
|
|
<ul>
|
|
<li>C++ exception handling is relied on to detect errors and clean up. In a complicated
|
|
function this is often a tremendous problem when writing in C. With PyCXX, we let the
|
|
compiler keep track of what objects need to be dereferenced when an error occurs.
|
|
<li>The Standard Template Library (STL) and its many algorithms plug and play with Python
|
|
containers such as lists and tuples.
|
|
<li>The optional CXX_Extensions facility allows you to replace the clumsy C tables with
|
|
objects and method calls that define your modules and extension objects.
|
|
</ul>
|
|
|
|
<h3>Download and Installation</h3>
|
|
|
|
<p>Download PyCXX from <a href="http://sourceforge.net/projects/cxx/">http://sourceforge.net/projects/cxx/</a>.</p>
|
|
|
|
<p>The distribution layout is:</p>
|
|
<table>
|
|
<tr><th>Directory</th><th>Description</th></tr>
|
|
<tr><td class=code>.</td><td>Makefile for Unix and Windows, Release documentation</td>
|
|
<tr><td class=code>./CXX</td><td>Header files</td>
|
|
<tr><td class=code>./Src</td><td>Source files</td>
|
|
<tr><td class=code>./Doc</td><td>Documentation</td>
|
|
<tr><td class=code>./Demo</td><td>Testing and Demonstartion files</td>
|
|
</table>
|
|
|
|
<p>To use PyCXX you use its include files and add its source routines to your module.</p>
|
|
|
|
<p>Installation:</p>
|
|
<ul>
|
|
<li>Install the PyCXX files into a directory of your choice. For example:<br>
|
|
Windows: <cite>C:\PyCXX</cite><br>
|
|
Unix: <cite>/usr/local/PyCXX</cite>
|
|
<li>Tell your compiler where the PyCXX header files are:<br>
|
|
Windows: <cite>cl /I=C:\PyCXX ...</cite><br>
|
|
Unix: <cite>g++ -I/usr/local/PyCXX ...</cite>
|
|
<li>Include PyCXX headers files in your code using the CXX prefix:<br>
|
|
<cite>#include "CXX/Object.hxx"</cite>
|
|
</ul>
|
|
|
|
<p>The header file CXX/config.h may need to be adjusted for the
|
|
compiler you use. As of this writing, only a fairly obscure reference to part of the
|
|
standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace
|
|
support and a standard C++ library. </p>
|
|
|
|
<h3>Use of namespaces</h3>
|
|
|
|
<p>All PyCXX assets are in namespace "Py". You need to include
|
|
the Py:: prefix when referring to them, or include the statement:</p>
|
|
|
|
<p>using namespace Py;</p>
|
|
|
|
<h2>Wrappers for standard objects: CXX_Objects.h</h2>
|
|
|
|
<p>Header file CXX_Objects.h requires adding file Src/cxxsupport.cxx to
|
|
your module sources. CXX_Objects provides a set of wrapper classes that allow you access
|
|
to most of the Python C API using a C++ notation that closely resembles Python. For
|
|
example, this Python:</p>
|
|
|
|
<pre>d = {}
|
|
d["a"] = 1
|
|
d["b"] = 2
|
|
alist = d.keys()
|
|
print alist</pre>
|
|
|
|
<p>Can be written in C++:</p>
|
|
|
|
<pre>Dict d;
|
|
List alist;
|
|
d["a"] = Int(1);
|
|
d["b"] = Int(2);
|
|
alist = d.keys();
|
|
std::cout << alist << std::endl;
|
|
</pre>
|
|
|
|
<p>You can optionally use the CXX/Extensions.hxx facility described later
|
|
to define Python extension modules and extension objects.</p>
|
|
|
|
<h3>We avoid programming with Python object pointers</h3>
|
|
|
|
<p>The essential idea is that we avoid, as much as possible, programming with pointers to
|
|
Python objects, that is, variables of type <cite>PyObject*</cite>. Instead,
|
|
we use instances of a family of C++ classes that represent the
|
|
usual Python objects. This family is easily extendible to include new kinds of Python
|
|
objects.</p>
|
|
|
|
<p>For example, consider the case in which we wish to write a method, taking a single
|
|
integer argument, that will create a Python <cite>dict</cite>
|
|
and insert into it that the integer plus one under the key <cite>value</cite>.
|
|
In C we might do that as follows:</p>
|
|
|
|
<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* args)
|
|
{
|
|
PyObject *d;
|
|
PyObject* f;
|
|
int k;
|
|
PyArgs_ParseTuple(args, "i", &k);
|
|
d = PyDict_New();
|
|
if (!d)
|
|
return NULL;
|
|
|
|
f = PyInt_NEW(k+1);
|
|
if(!f)
|
|
{
|
|
Py_DECREF(d); /* have to get rid of d first */
|
|
return NULL;
|
|
}
|
|
if(PyDict_SetItemString(d, "value", f) == -1)
|
|
{
|
|
Py_DECREF(f);
|
|
Py_DECREF(d);
|
|
return NULL;
|
|
}
|
|
|
|
return d;
|
|
}</pre>
|
|
|
|
<p>If you have written a significant Python extension, this tedium looks all too familiar.
|
|
The vast bulk of the coding is error checking and cleanup. Now compare the same thing
|
|
written in C++ using CXX/Objects.hxx. The things with Python-like names (Int, Dict, Tuple) are
|
|
from CXX/Objects.hxx.</p>
|
|
|
|
<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* pargs)
|
|
{
|
|
try {
|
|
Tuple args(pargs);
|
|
args.verify_length(1);
|
|
|
|
Dict d;
|
|
Int k = args[0];
|
|
d["value"] = k + 1;
|
|
|
|
return new_reference_to(d);
|
|
}
|
|
catch (const PyException&)
|
|
{
|
|
return NULL;
|
|
}
|
|
}</pre>
|
|
|
|
<p>If there are not the right number of arguments or the argument is not an
|
|
integer, an exception is thrown. In this case we choose to catch it and convert it into a
|
|
Python exception. The C++ exception handling mechanism takes care all the cleanup.</p>
|
|
|
|
<p>Note that the creation of the <cite>Int k</cite> got the first argument <em>and</em> verified
|
|
that it is an <cite>Int</cite>.</p>
|
|
|
|
<p>Just to peek ahead, if you wrote this method in an
|
|
ExtensionModule-derived module of your own, it would be a method and it could be written
|
|
even more simply:</p>
|
|
|
|
<pre>
|
|
Object addvalue (Object & self, const Tuple & args)
|
|
{
|
|
args.verify_length(1);
|
|
Dict d;
|
|
Int k = args[0];
|
|
d["value"] = k + 1;
|
|
return d;
|
|
}
|
|
</pre>
|
|
|
|
<h2>The basic concept is to wrap Python pointers</h2>
|
|
|
|
|
|
<p>The basic concept of CXX/Objects.hxx is to create a wrapper around
|
|
each <cite>PyObject *</cite> so that the reference counting can be
|
|
done automatically, thus eliminating the most frequent source of errors. In addition, we
|
|
can then add methods and operators so that Python objects can be manipulated in C++
|
|
much like you would in Python.</p>
|
|
|
|
<p>Each <cite>Object</cite> contains a <cite>PyObject *</cite>
|
|
to which it owns a reference. When an <cite>Object</cite> is destroyed, it releases its ownership on
|
|
the pointer. Since C++ calls the destructors on objects that are about to go out of scope,
|
|
we are guaranteed that we will keep the reference counts right even if we unexpectedly
|
|
leave a routine with an exception.</p>
|
|
|
|
<p>As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its
|
|
classes unless the instance will be a valid instance of its class. When an attempt is made
|
|
to create an object that will not be valid, an exception is thrown.</p>
|
|
|
|
<p>Class <cite>Object</cite> represents the most general kind of Python object. The rest of the classes
|
|
that represent Python objects inherit from it.</p>
|
|
|
|
<pre>Object
|
|
Type
|
|
Int
|
|
Float
|
|
Long
|
|
Complex
|
|
Char
|
|
Sequence -> SeqBase<T>
|
|
String
|
|
Tuple
|
|
List
|
|
Mapping -> MapBase<T>
|
|
Dict
|
|
Callable
|
|
Module</pre>
|
|
|
|
<p>There are several constructors for each of these classes. For example, you can create
|
|
an <cite>Int</cite> from an integer as in</p>
|
|
|
|
<pre>Int s(3)</pre>
|
|
|
|
<p>However, you can also create an instance of one of these classes using any <cite>PyObject*</cite> or
|
|
another <cite>Object</cite>. If the corresponding Python object does not actually have the type
|
|
desired, an exception is thrown. This is accomplished as follows. Class <cite>Object</cite> defines a
|
|
virtual function <cite>accepts</cite>:</p>
|
|
|
|
<pre>virtual bool accepts(PyObject* p)</pre>
|
|
|
|
<p>The base class version of <cite>accepts</cite> returns true for any pointer p except 0. This means
|
|
we can create an Object using any <cite>PyObject *</cite>, or from any other
|
|
<cite>Object</cite>. However, if we attempt to create an <cite>Int</cite> from a <cite>PyObject *</cite>,
|
|
the overridding version
|
|
of <cite>accepts</cite> in class <cite>Int</cite> will only accept pointers that correspond to Python ints.
|
|
Therefore if we have a <cite>Tuple t</cite> and we wish to get the first element and be sure it is an
|
|
<cite>Int</cite>, we do</p>
|
|
|
|
<pre>Int first_element = t[0]</pre>
|
|
|
|
<p>This will not only accomplish the goal of extracting the first element of the <cite>Tuple t</cite>,
|
|
but it will ensure that the result is an <cite>Int</cite>. If not, an exception is thrown. The
|
|
exception mechanism is discussed later.</p>
|
|
|
|
<h2>Class Object</h2>
|
|
|
|
<p>Class <cite>Object</cite> serves as the base class for the other classes. Its default constructor
|
|
constructs a <cite>Py_None</cite>, the unique object of Python type <cite>None</cite>. The interface to <cite>Object</cite>
|
|
consists of a large number of methods corresponding to the operations that are defined for
|
|
every Python object. In each case, the methods throw an exception if anything goes
|
|
wrong.</p>
|
|
|
|
<p>There is no method corresponding to <cite>PyObject_SetItem</cite> with an arbitrary Python object
|
|
as a key. Instead, create an instance of a more specific child of <cite>Object</cite> and use the
|
|
appropriate facilities.</p>
|
|
|
|
<p>The comparison operators use the Python comparison function to compare values. The
|
|
method <cite>is</cite> is available to test for absolute identity.</p>
|
|
|
|
<p>A conversion to standard library string type <cite>std::string</cite> is supplied using method
|
|
<cite>as_string</cite>. Stream output of PyCXX <cite>Object</cite> instances uses this conversion,
|
|
which in turn uses the Python object's str() representation.</p>
|
|
|
|
<p>All the numeric operators are defined on all possible combinations of <cite>Object</cite>,
|
|
<cite>long</cite>, and <cite>double</cite>. These use the corresponding Python operators,
|
|
and should the operation fail for some reason, an exception is thrown.</p>
|
|
|
|
<h3>Dealing with pointers returned by the Python C API</h3>
|
|
|
|
<p>Often, <cite>PyObject *</cite> pointers are acquired from some function,
|
|
particularly functions in the Python C API. If you wish to make an object from the pointer
|
|
returned by such a function, you need to know if the function returns you an <i>owned</i>
|
|
or <i>unowned</i> reference. Unowned references are unusual but there are some cases where
|
|
unowned references are returned.</p>
|
|
|
|
<p>Usually, <cite>Object</cite> and its children acquire a new reference when constructed from a
|
|
<cite>PyObject *</cite>. This is usually not the right behavior if the reference comes from one
|
|
of the Python C API calls.</p>
|
|
|
|
<p>If p is an owned reference, you can add the boolean <cite>true</cite> as an extra
|
|
argument in the creation routine, <cite>Object(p, true)</cite>, or use the function <cite>asObject(p)</cite> which
|
|
returns an <cite>Object</cite> created using the owned reference. For example, the routine
|
|
<cite>PyString_FromString</cite> returns an owned reference to a Python string object. You could write:</p>
|
|
|
|
<pre>Object w = asObject( PyString_FromString("my string") );</pre>
|
|
|
|
<p>or using the constructor,</p>
|
|
|
|
<pre>Object w( PyString_FromString("my string"), true );</pre>
|
|
|
|
<p>In fact, you would never do this, since PyCXX has a class String and you can just say: </p>
|
|
|
|
<pre>String w( "my string" );</pre>
|
|
|
|
<p>Indeed, since most of the Python C API is similarly embodied in <cite>Object</cite>
|
|
and its descendents, you probably will not use asObject all that often.</p>
|
|
<h3>Table 1: Class Object</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Returns</th>
|
|
<th>Name(signature)</th>
|
|
<th>Comment</th>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3"><p align="center"><strong>Basic Methods</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>Object (PyObject* pyob=Py_None, bool owned=false) </td>
|
|
<td>Construct from pointer. </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Object (const Object& ob)</td>
|
|
<td>Copycons; acquires an owned reference.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object&</td>
|
|
<td class=code>operator= (const Object& rhs) </td>
|
|
<td>Acquires an owned reference.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object&</td>
|
|
<td class=code>operator= (PyObject* rhsp) </td>
|
|
<td>Acquires an owned reference.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual</td>
|
|
<td class=code>~Object () </td>
|
|
<td>Releases the reference.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>increment_reference_count() </td>
|
|
<td>Explicitly increment the count</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>decrement_reference_count()</td>
|
|
<td>Explicitly decrement count but not to zero</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>PyObject*</td>
|
|
<td class=code>operator* () const</td>
|
|
<td>Lends the pointer</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>PyObject*</td>
|
|
<td class=code>ptr () const</td>
|
|
<td>Lends the pointer</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool</td>
|
|
<td class=code>accepts (PyObject *pyob) const</td>
|
|
<td>Would assignment of pyob to this object succeed?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>std::string</td>
|
|
<td class=code>as_string() const</td>
|
|
<td>str() representation</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3" align="center"><strong>Python API Interface</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>int</td>
|
|
<td class=code>reference_count () const </td>
|
|
<td>reference count</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Type</td>
|
|
<td class=code>type () const</td>
|
|
<td>associated type object</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>String</td>
|
|
<td class=code>str () const</td>
|
|
<td>str() representation</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>String</td>
|
|
<td class=code>repr () const</td>
|
|
<td>repr () representation</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>hasAttr (const std::string& s) const</td>
|
|
<td>hasattr(this, s)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object</td>
|
|
<td class=code>getAttr (const std::string& s) const</td>
|
|
<td>getattr(this, s)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object</td>
|
|
<td class=code>getItem (const Object& key) const</td>
|
|
<td>getitem(this, key)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>long</td>
|
|
<td class=code>hashValue () const</td>
|
|
<td>hash(this)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>setAttr (const std::string& s,<br>const Object& value)</td>
|
|
<td>this.s = value</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>delAttr (const std::string& s) </td>
|
|
<td>del this.s</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>delItem (const Object& key) </td>
|
|
<td>del this[key]</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isCallable () const</td>
|
|
<td>does this have callable behavior?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isList () const</td>
|
|
<td>is this a Python list?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isMapping () const</td>
|
|
<td>does this have mapping behaviors?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isNumeric () const</td>
|
|
<td>does this have numeric behaviors?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isSequence () const </td>
|
|
<td>does this have sequence behaviors?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isTrue () const</td>
|
|
<td>is this true in the Python sense?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isType (const Type& t) const</td>
|
|
<td>is type(this) == t?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isTuple() const</td>
|
|
<td>is this a Python tuple?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isString() const</td>
|
|
<td>is this a Python string?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isUnicode() const</td>
|
|
<td>is this a Python Unicode string?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>isDict() const</td>
|
|
<td>is this a Python dictionary?</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3" align="center"><strong>Comparison Operators</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>is(PyObject* pother) const</td>
|
|
<td>test for identity</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>is(const Object& other) const</td>
|
|
<td>test for identity</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool </td>
|
|
<td class=code>operator==(const Object& o2) const</td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>operator!=(const Object& o2) const</td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>operator>=(const Object& o2) const</td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>operator<=(const Object& o2) const </td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>operator<(const Object& o2) const</td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>bool</td>
|
|
<td class=code>operator>(const Object& o2) const</td>
|
|
<td>Comparisons use Python cmp</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h1>The Basic Types</h1>
|
|
|
|
<p>Corresponding to each of the basic Python types is a class that inherits from Object.
|
|
Here are the interfaces for those types. Each of them inherits from Object and therefore
|
|
has all of the inherited methods listed for Object. Where a virtual function is overridden
|
|
in a class, the name is underlined. </p>
|
|
|
|
<h2>Class Type</h2>
|
|
|
|
<p>Class Type corresponds to Python type objects. There is no default constructor.</p>
|
|
|
|
<h3>Table 2: class Type</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Returns</th>
|
|
<th>Name and Signature</th>
|
|
<th>Comments</th>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Type (PyObject* pyob, bool owned = false)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Type (const Object& ob)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Type(const Type& t)</td>
|
|
<td>Copycons</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Type&</td>
|
|
<td class=code>operator= (const Object& rhs) </td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Type&</td>
|
|
<td class=code>operator= (PyObject* rhsp) </td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool</td>
|
|
<td class=code><u>accepts</u> (PyObject *pyob) const</td>
|
|
<td>Uses PyType_Check</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Class Int</h2>
|
|
|
|
<p>Class Int, derived publically from Object, corresponds to Python ints. Note that the
|
|
latter correspond to C long ints. Class Int has an implicit user-defined conversion to
|
|
long int. All constructors, on the other hand, are explicit. The default constructor
|
|
creates a Python int zero.</p>
|
|
|
|
<h3>Table 3: class Int</h3>
|
|
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Returns</td>
|
|
<th>Name and Signature</td>
|
|
<th>Comments</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Int (PyObject *pyob, bool owned= false, bool owned = false)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Int (const Int& ob)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Int (long v = 0L)</td>
|
|
<td>Construct from long</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Int (int v)</td>
|
|
<td>Contruct from int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Int (const Object& ob)</td>
|
|
<td>Copycons</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Int&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Int&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool </td>
|
|
<td class=code> (PyObject *pyob) const </td>
|
|
<td>Based on PyInt_Check</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>long</td>
|
|
<td class=code>operator long() const </td>
|
|
<td><em>Implicit</em> conversion to long int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Int&</td>
|
|
<td class=code>operator= (int v)</td>
|
|
<td>Assign from int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Int&</td>
|
|
<td class=code>operator= (long v) </td>
|
|
<td>Assign from long</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<hr>
|
|
|
|
<h2>Class Long</h2>
|
|
|
|
<p>Class Long, derived publically from Object, corresponds to Python type long. In Python,
|
|
a long is an integer type of unlimited size, and is usually used for applications such as
|
|
cryptography, not as a normal integer. Implicit conversions to both double and long are
|
|
provided, although the latter may of course fail if the number is actually too big. All
|
|
constructors are explicit. The default constructor produces a Python long zero.</p>
|
|
|
|
<h3>Table 4: Class Long</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Returns</td>
|
|
<th>Name and Signature</td>
|
|
<th>Comments</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Long (PyObject *pyob</a>, bool owned = false)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Long (const Int& ob)</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Long (long v = 0L)</td>
|
|
<td>Construct from long</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Long (int v)</td>
|
|
<td>Contruct from int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Long (const Object& ob)</td>
|
|
<td>Copycons</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Long&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Long&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool</td>
|
|
<td class=code>(PyObject *pyob) const </td>
|
|
<td>Based on PyLong_Check</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>double</td>
|
|
<td class=code>operator double() const </td>
|
|
<td><em>Implicit</em> conversion to double</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>long</td>
|
|
<td class=code>operator long() const</td>
|
|
<td><em>Implicit</em> conversion to long</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Long&</td>
|
|
<td class=code>operator= (int v)</td>
|
|
<td>Assign from int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Long&</td>
|
|
<td class=code>operator= (long v) </td>
|
|
<td>Assign from long</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Class Float</h2>
|
|
|
|
<p>Class Float corresponds to Python floats, which in turn correspond to C double. The
|
|
default constructor produces the Python float 0.0. </p>
|
|
|
|
<h3>Table 5: Class Float</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Returns</td>
|
|
<th>Name and Signature</td>
|
|
<th>Comments</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Float (PyObject *pyob</a>, bool owned = false)
|
|
</td>
|
|
<td>Constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Float (const Float& f) </td>
|
|
<td>Construct from float</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Float (double v=0.0)</td>
|
|
<td>Construct from double</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Float (const Object& ob)</td>
|
|
<td>Copycons</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool </td>
|
|
<td class=code>accepts (PyObject *pyob) const</td>
|
|
<td>Based on PyFloat_Check</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>double </td>
|
|
<td class=code>operator double () const</td>
|
|
<td><em>Implicit</em> conversion to double</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float& </td>
|
|
<td class=code>operator= (double v)</td>
|
|
<td>Assign from double</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float& </td>
|
|
<td class=code>operator= (int v)</td>
|
|
<td>Assign from int</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float& </td>
|
|
<td class=code>operator= (long v)</td>
|
|
<td>Assign from long</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Float& </td>
|
|
<td class=code>operator= (const Int& iob)</td>
|
|
<td>Assign from Int</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h1>Sequences</h1>
|
|
|
|
<p>PyCXX implements a quite sophisticated wrapper class for Python sequences. While every
|
|
effort has been made to disguise the sophistication, it may pop up in the form of obscure
|
|
compiler error messages, so in this documentation we will first detail normal usage and
|
|
then discuss what is under the hood.</p>
|
|
|
|
<p>The basic idea is that we would like the subscript operator [] to work properly, and to
|
|
be able to use STL-style iterators and STL algorithms across the elements of the sequence.</p>
|
|
|
|
<p>Sequences are implemented in terms of a templated base class, SeqBase<T>. The
|
|
parameter T is the answer to the question, sequence of what? For Lists, for example, T is
|
|
Object, because the most specific thing we know about an element of a List is simply that
|
|
it is an Object. (Class List is defined below; it is a descendent of Object that holds a
|
|
pointer to a Python list). For strings, T is Char, which is a wrapper in turn of Python
|
|
strings whose length is one.</p>
|
|
|
|
<p>For convenience, the word <strong>Sequence</strong> is a typedef of SeqBase<Object>.</p>
|
|
|
|
<h2>General sequences</h2>
|
|
|
|
<p>Suppose you are writing an extension module method that expects the first argument to
|
|
be any kind of Python sequence, and you wish to return the length of that sequence. You
|
|
might write:</p>
|
|
|
|
<pre>static PyObject*
|
|
my_module_seqlen (PyObject *self, PyObject* args) {
|
|
try
|
|
{
|
|
Tuple t(args); // set up a Tuple pointing to the arguments.
|
|
if(t.length() != 1)
|
|
throw PyException("Incorrect number of arguments to seqlen.");
|
|
Sequence s = t[0]; // get argument and be sure it is a sequence
|
|
return new_reference_to(Int(s.length()));
|
|
}
|
|
catch(const PyException&)
|
|
{
|
|
return Py_Null;
|
|
}
|
|
}</pre>
|
|
|
|
<p>As we will explain later, the try/catch structure converts any errors, such as the
|
|
first argument not being a sequence, into a Python exception.</p>
|
|
|
|
<h3>Subscripting</h3>
|
|
|
|
<p>When a sequence is subscripted, the value returned is a special kind of object which
|
|
serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers'
|
|
book, "More Effective C++". Proxy objects are necessary because when one
|
|
subscripts a sequence it is not clear whether the value is to be used or the location
|
|
assigned to. Our proxy object is even more complicated than normal because a sequence
|
|
reference such as s[i] is not a direct reference to the i'th object of s. </p>
|
|
|
|
<p>In normal use, you are not supposed to notice this magic going on behind your back. You
|
|
write:</p>
|
|
|
|
<pre>Object t;
|
|
Sequence s;
|
|
s[2] = t + s[1]</pre>
|
|
|
|
<p>and here is what happens: s[1] returns a proxy object. Since there is no addition
|
|
operator in Object that takes a proxy as an argument, the compiler decides to invoke an
|
|
automatic conversion of the proxy to an Object, which returns the desired component of s.
|
|
The addition takes place, and then there is an assignment operator in the proxy class
|
|
created by the s[2], and that assignment operator stuffs the result into the 2 component
|
|
of s.</p>
|
|
|
|
<p>It is possible to fool this mechanism and end up with a compiler failing to admit that
|
|
a s[i] is an Object. If that happens, you can work around it by writing Object(s[i]),
|
|
which makes the desired implicit conversion, explicit.</p>
|
|
|
|
<h3>Iterators</h3>
|
|
|
|
<p>Each sequence class provides the following interface. The class seqref<T> is the
|
|
proxy class. We omit the details of the iterator, const_iterator, and seqref<T>
|
|
here. See CXX_Objects.h if necessary. The purpose of most of this interface is to satisfy
|
|
requirements of the STL.</p>
|
|
|
|
<h3>The SeqBase<T> Interface</h3>
|
|
|
|
<p>SeqBase<T> inherits from Object.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>typedef int </td>
|
|
<td class=code>size_type</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>typedef seqref<T></td>
|
|
<td class=code>reference</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>typedef T </td>
|
|
<td class=code>const_reference</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>typedef seqref<T>*</td>
|
|
<td class=code>pointer</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>typedef int </td>
|
|
<td class=code>difference_type</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual size_type</td>
|
|
<td class=code>max_size() const</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual size_type </td>
|
|
<td class=code>capacity() const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual void </td>
|
|
<td class=code>swap(SeqBase<T>& c);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual size_type </td>
|
|
<td class=code>size () const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>SeqBase<T> ();</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>SeqBase<T> (PyObject* pyob, bool owned = false);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>SeqBase<T> (const Object& ob);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>SeqBase<T>& </td>
|
|
<td class=code>operator= (const Object& rhs);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>SeqBase<T>& </td>
|
|
<td class=code>operator= (PyObject* rhsp);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual bool </td>
|
|
<td class=code>accepts (PyObject *pyob) const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>size_type </td>
|
|
<td class=code>length () const ;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>const T </td>
|
|
<td class=code>operator[](size_type index) const; </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>seqref<T> </td>
|
|
<td class=code>operator[](size_type index); </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual T </td>
|
|
<td class=code>getItem (size_type i) const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual void </td>
|
|
<td class=code>setItem (size_type i, const T& ob);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>SeqBase<T> </td>
|
|
<td class=code>repeat (int count) const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>SeqBase<T> </td>
|
|
<td class=code>concat (const SeqBase<T>& other) const ;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>const T </td>
|
|
<td class=code>front () const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>seqref<T> </td>
|
|
<td class=code>front();</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>const T </td>
|
|
<td class=code>back () const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>seqref<T> </td>
|
|
<td class=code>back(); </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>verify_length(size_type required_size);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>verify_length(size_type min_size, size_type max_size);</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>class</td>
|
|
<td class=code>iterator;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>iterator </td>
|
|
<td class=code>begin (); </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>iterator </td>
|
|
<td class=code>end ();</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>class </td>
|
|
<td class=code>const_iterator;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>const_iterator </td>
|
|
<td class=code>begin () const;</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>const_iterator </td>
|
|
<td class=code>end () const;</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>Any heir of class Object that has a sequence behavior should inherit from class
|
|
SeqBase<T>, where T is specified as the type of object that represents the
|
|
individual elements of the sequence. The requirements on T are that it has a constructor
|
|
that takes a PyObject* as an argument, that it has a default constructor, a copy
|
|
constructor, and an assignment operator. In short, any properly defined heir of Object
|
|
will work. </p>
|
|
|
|
<h2>Classes Char and String</h2>
|
|
|
|
<p>Python strings are unusual in that they are immutable sequences of characters. However,
|
|
there is no character type per se; rather, when subscripted strings return a string of
|
|
length one. To simulate this, we define two classes Char and String. The Char class
|
|
represents a Python string object of length one. The String class represents a Python
|
|
string, and its elements make up a sequence of Char's.</p>
|
|
|
|
<p>The user interface for Char is limited. Unlike String, for example, it is not a
|
|
sequence.</p>
|
|
|
|
<h3>The Char interface</h3>
|
|
|
|
<p>Char inherits from Object.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Char (PyObject *pyob, bool owned = false)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Char (const Object& ob) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Char (const std::string& v = "") </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Char (char v)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Char (Py_UNICODE v)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Char&</td>
|
|
<td class=code>operator= (const std::string& v)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Char&</td>
|
|
<td class=code>operator= (char v) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Char&</td>
|
|
<td class=code>operator= (Py_UNICODE v) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Char&</td>
|
|
<td class=code>operator= (std::basic_string<Py_UNICODE> v) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>operator String() const</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>operator std::string () const </td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>The String Interface</h3>
|
|
|
|
<p>String inherits from SeqBase<Char>.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>String (PyObject *pyob, bool owned = false)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const Object& ob)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const std::string& v = "")</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const std::string& v, const char *encoding, const char *error="strict")</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const char *s, const char *encoding, const char *error="strict")</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const char *s, int len, const char *encoding, const char *error="strict")</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const std::string& v, std::string::size_type vsize)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>String (const char* v)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>String&</td>
|
|
<td class=code>operator= (const std::string& v) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>std::string</td>
|
|
<td class=code>operator std::string () const</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>String</td>
|
|
<td class=code>encode( const char *encoding, const char *error="strict" )</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>String</td>
|
|
<td class=code>decode( const char *encoding, const char *error="strict" )</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>std::string</td>
|
|
<td class=code>as_std_string() const</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>unicodestring</td>
|
|
<td class=code>as_unicodestring() const</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Class Tuple</h2>
|
|
|
|
<p>Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of
|
|
constructors: one takes a PyObject* as usual, the other takes an integer number as an
|
|
argument and returns a Tuple of that length, each component initialized to Py_None. The
|
|
default constructor produces an empty Tuple. </p>
|
|
|
|
<p>Tuples are not immutable, but attempts to assign to their components will fail if the
|
|
reference count is not 1. That is, it is safe to set the elements of a Tuple you have just
|
|
made, but not thereafter.</p>
|
|
|
|
<p>Example: create a Tuple containing (1, 2, 4)</p>
|
|
|
|
<pre>Tuple t(3)
|
|
t[0] = Int(1)
|
|
t[1] = Int(2)
|
|
t[2] = Int(4)</pre>
|
|
|
|
<p>Example: create a Tuple from a list:</p>
|
|
|
|
<pre>Dict d
|
|
...
|
|
Tuple t(d.keys())</pre>
|
|
|
|
<h3>The Tuple Interface</h3>
|
|
|
|
<p>Tuple inherits from Sequence.. Special run-time checks prevent modification if the
|
|
reference count is greater than one.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual void</td>
|
|
<td class=code>setItem (int offset, const Object&ob) </td>
|
|
<td>setItem is overriden to handle tuples properly. </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Tuple (PyObject *pyob, bool owned = false)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>Tuple (const Object& ob)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Tuple (int size = 0)</td>
|
|
<td>Create a tuple of the given size. Items initialize to Py_None. Default is an empty
|
|
tuple.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Tuple (const Sequence& s)</td>
|
|
<td>Create a tuple from any sequence.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Tuple&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Tuple&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Tuple</td>
|
|
<td class=code>getSlice (int i, int j) const </td>
|
|
<td>Equivalent to python's t[i:j]</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Class List</h2>
|
|
|
|
<p>Class List represents a Python list, and the methods available faithfully reproduce the
|
|
Python API for lists. A List is a Sequence.</p>
|
|
|
|
<h3>The List Interface</h3>
|
|
|
|
<p>List inherits from Sequence.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>List (PyObject *pyob, bool owned = false)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>List (const Object& ob)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>List (int size = 0)</td>
|
|
<td>Create a list of the given size. Items initialized to Py_None. Default is an empty list.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>List (const Sequence& s)</td>
|
|
<td>Create a list from any sequence.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List</td>
|
|
<td class=code>getSlice (int i, int j) const</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>setSlice (int i, int j, const Object& v) </td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>append (const Object& ob)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>insert (int i, const Object& ob)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>sort ()</td>
|
|
<td>Sorts the list in place, using Python's member function. You can also use
|
|
the STL sort function on any List instance.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>reverse ()</td>
|
|
<td>Reverses the list in place, using Python's member function.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h1>Mappings</h1>
|
|
|
|
<p>A class MapBase<T> is used as the base class for Python objects with a mapping
|
|
behavior. The key behavior of this class is the ability to set and use items by
|
|
subscripting with strings. A proxy class mapref<T> is defined to produce the correct
|
|
behavior for both use and assignment.</p>
|
|
|
|
<p>For convenience, <cite>Mapping</cite> is a typedef for <cite>MapBase<Object></cite>.</p>
|
|
|
|
<h3>The MapBase<T> interface</h3>
|
|
|
|
<p>MapBase<T> inherits from Object. T should be chosen to reflect the kind of
|
|
element returned by the mapping.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>T</td>
|
|
<td class=code>operator[](const std::string& key) const</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>mapref<T> </td>
|
|
<td class=code>operator[](const std::string& key)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>int</td>
|
|
<td class=code>length () const</td>
|
|
<td>Number of entries.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>int</td>
|
|
<td class=code>hasKey (const std::string& s) const </td>
|
|
<td>Is m[s] defined?</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>T</td>
|
|
<td class=code>getItem (const std::string& s) const</td>
|
|
<td>m[s]</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual void</td>
|
|
<td class=code>setItem (const std::string& s, const Object& ob)</td>
|
|
<td>m[s] = ob</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>delItem (const std::string& s)</td>
|
|
<td>del m[s]</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>delItem (const Object& s)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List</td>
|
|
<td class=code>keys () const</td>
|
|
<td>A list of the keys.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List</td>
|
|
<td class=code>values () const</td>
|
|
<td>A list of the values.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>List</td>
|
|
<td class=code>items () const</td>
|
|
<td>Each item is a key-value pair.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Class Dict</h2>
|
|
|
|
<p>Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to
|
|
subscripts can be used to set the components.</p>
|
|
|
|
<pre>Dict d
|
|
d["Paul Dubois"] = "(925)-422-5426"</pre>
|
|
|
|
<h3>Interface for Class Dict</h3>
|
|
|
|
<p>Dict inherits from MapBase<Object>.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Dict (PyObject *pyob</a>, bool owned = false)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>Dict (const Dict& ob)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>Dict () </td>
|
|
<td>Creates an empty dictionary</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Dict&</td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Dict&</td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h1>Other classes and facilities.</h1>
|
|
|
|
<p>Class Callable provides an interface to those Python objects that support a call
|
|
method. Class Module holds a pointer to a module. If you want to create an extension
|
|
module, however, see the extension facility. There is a large set of numeric operators.</p>
|
|
|
|
<h3>Interface to class Callable</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Callable (PyObject *pyob</a>, bool owned = false)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Callable& </td>
|
|
<td class=code>operator= (const Object& rhs)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Callable& </td>
|
|
<td class=code>operator= (PyObject* rhsp)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object</td>
|
|
<td class=code>apply(const Tuple& args) const</td>
|
|
<td>Call the object with the given arguments</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Object</td>
|
|
<td class=code>apply(PyObject* pargs = 0) const </td>
|
|
<td>Call the object with args as the arguments. Checks that pargs is a tuple.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Interface to class Module</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Module (PyObject* pyob, bool owned = false)</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>Module (const std::string name)</td>
|
|
<td>Construct from name of module; does the import if needed.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td class=code>Module (const Module& ob) </td>
|
|
<td>Copy constructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Module&</td>
|
|
<td class=code>operator= (const Object& rhs) </td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Module&</td>
|
|
<td class=code>operator= (PyObject* rhsp) </td>
|
|
<td>Assignment</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Numeric interface</h3>
|
|
|
|
<p>Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined
|
|
for pairs of objects and for objects with scalar integers or doubles (in either
|
|
order). Functions abs(ob) and coerce(o1, o2) are also defined. </p>
|
|
|
|
<p>The signature for coerce is:</p>
|
|
|
|
<pre>inline std::pair<Object,Object> coerce(const Object& a, const Object& b)</pre>
|
|
|
|
<p>Unlike the C API function, this simply returns the pair after coercion.</p>
|
|
|
|
<h3>Stream I/O</h3>
|
|
|
|
<p>Any object can be printed using stream I/O, using std::ostream& operator<<
|
|
(std::ostream& os, const Object& ob). The object's str() representation is
|
|
converted to a standard string which is passed to std::ostream& operator<<
|
|
(std::ostream& os, const std::string&).</p>
|
|
|
|
<h2>Exceptions</h2>
|
|
|
|
<p>The Python exception facility and the C++ exception facility can be merged via the use
|
|
of try/catch blocks in the bodies of extension objects and module functions.</p>
|
|
|
|
<h3>Class Exception and its children</h3>
|
|
|
|
<p>A set of classes is provided. Each is derived from class Exception, and represents a
|
|
particular sort of Python exception, such as IndexError, RuntimeError, ValueError. Each of
|
|
them (other than Exception) has a constructor which takes an explanatory string as an
|
|
argument, and is used in a throw statement such as:</p>
|
|
|
|
<pre>throw IndexError("Index too large in MyObject access.");</pre>
|
|
|
|
<p>If in using a routine from the Python API, you discover that it has returned a NULL
|
|
indicating an error, then Python has already set the error message. In that case you
|
|
merely throw Exception.</p>
|
|
|
|
<h3>List of Exceptions</h3>
|
|
|
|
<p>The exception hierarchy mirrors the Python exception hierarchy. The concrete exception
|
|
classes are shown here.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Interface for class Exception</th>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit </td>
|
|
<td class=code>Exception()</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>Exception (const std::string& reason) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>Exception (PyObject* exception, const std::string& reason) </td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>clear()</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code></td>
|
|
<td>Constructors for other children of class Exception</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>TypeError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>IndexError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>AttributeError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>NameError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>RuntimeError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>SystemError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>KeyError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>ValueError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>OverflowError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>ZeroDivisionError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>MemoryError (const std::string& reason)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code> </td>
|
|
<td class=code>SystemExit (const std::string& reason)</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Using Exceptions in extension methods</h2>
|
|
|
|
<p>The exception facility allows you to integrate the C++ and Python exception mechanisms.
|
|
To do this, you must use the style described below when writing module methods in the old
|
|
C style. </p>
|
|
|
|
<p>Note: If using the ExtensionModule or PythonExtension mechanisms described below, the
|
|
method handlers include exception handling so that you only need to use exceptions
|
|
explicitly in unusual cases.</p>
|
|
|
|
<h3>Catching Exceptions from the Python API or PyCXX.</h3>
|
|
|
|
<p>When writing an extension module method, you can use the following boilerplate. Any
|
|
exceptions caused by the Python API or PyCXX itself will be converted into a Python
|
|
exception. Note that Exception is the most general of the exceptions listed above, and
|
|
therefore this one catch clause will serve to catch all of them. You may wish to catch
|
|
other exceptions, not in the Exception family, in the same way. If so, you need to make
|
|
sure you set the error in Python before returning.</p>
|
|
|
|
<pre>static PyObject *
|
|
some_module_method(PyObject* self, PyObject* args)
|
|
{
|
|
Tuple a(args); // we know args is a Tuple
|
|
try {
|
|
...calculate something from a...
|
|
return ...something, usually of the form new_reference_to(some Object);
|
|
}
|
|
catch(const Exception&) {
|
|
//Exception caught, passing it on to Python
|
|
return Null ();
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<h3>How to clear an Exception</h3>
|
|
|
|
<p>If you anticipate that an Exception may be thrown and wish to recover from it, change
|
|
the catch phrase to set a reference to an Exception, and use the method clear() from class
|
|
Exception to clear it.:</p>
|
|
|
|
<pre>catch(Exception& e)
|
|
{
|
|
e.clear();
|
|
...now decide what to do about it...
|
|
}
|
|
</pre>
|
|
|
|
<h2>Extension Facilities</h2>
|
|
|
|
<p>CXX/Extensions.hxx provides facilities for:
|
|
|
|
<ul>
|
|
<li>Creating a Python extension module</li>
|
|
<li>Creating new Python extension types</li>
|
|
</ul>
|
|
|
|
<p>These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.</p>
|
|
|
|
<p>If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and
|
|
cxx_extensions.cxx</p>
|
|
|
|
<h3>Creating an Python extension module</h3>
|
|
|
|
<p>The usual method of creating a Python extension module is to declare and initialize its
|
|
method table in C. This requires knowledge of the correct form for the table and the order
|
|
in which entries are to be made into it, and requires casts to get everything to compile
|
|
without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a
|
|
sample usage, in which a module named "example" is created. Note that two
|
|
details are necessary:
|
|
|
|
<ul>
|
|
<li>The initialization function must be declared to have external C linkage and to have the
|
|
expected name. This is a requirement imposed by Python</li>
|
|
<li>The ExtensionModule object must have a storage class that survives the call to the
|
|
initialization function. This is most easily accomplished by using a static local inside
|
|
the initialization function, as in initexample below.</li>
|
|
</ul>
|
|
|
|
<p>To create an extension module, you inherit from class ExtensionModule templated on
|
|
yourself: In the constructor, you make calls to register methods of this class with Python
|
|
as extension module methods. In this example, two methods are added (this is a simplified
|
|
form of the example in Demo/example.cxx):</p>
|
|
|
|
<pre>class example_module : public ExtensionModule<example_module>
|
|
{
|
|
public:
|
|
example_module()
|
|
: ExtensionModule<example_module>( "example" )
|
|
{
|
|
add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments");
|
|
add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite");
|
|
|
|
initialize( "documentation for the example module" );
|
|
}
|
|
|
|
virtual ~example_module() {}
|
|
|
|
private:
|
|
Object ex_sum(const Tuple &a) { ... }
|
|
Object ex_test(const Tuple &a) { ... }
|
|
};
|
|
</pre>
|
|
|
|
<p>To initialize the extension, you just instantiate one static instance (static so it
|
|
does not destroy itself!):</p>
|
|
|
|
<pre>void initexample()
|
|
{
|
|
static example_module* example = new example_module;
|
|
}</pre>
|
|
|
|
<p>The methods can be written to take Tuples as arguments and return Objects. If
|
|
exceptions occur they are trapped for you and a Python exception is generated. So, for
|
|
example, the implementation of ex_sum might be:</p>
|
|
|
|
<pre>Object ex_sum (const Tuple &a)
|
|
{
|
|
Float f(0.0);
|
|
for( int i = 0; i < a.length(); i++ )
|
|
{
|
|
Float g(a[i]);
|
|
f = f + g;
|
|
}
|
|
return f;
|
|
}</pre>
|
|
|
|
<p>class ExtensionModule contains methods to return itself as a Module object, or to
|
|
return its dictionary.</p>
|
|
|
|
<h3>Interface to class ExtensionModule</h3>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>explicit</td>
|
|
<td class=code>ExtensionModule (char* name) </td>
|
|
<td>Create an extension module named "name"</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual </td>
|
|
<td class=code>~ExtensionModule () </td>
|
|
<td>Destructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Dict</td>
|
|
<td class=code>moduleDictionary() const</td>
|
|
<td>Returns the module dictionary; module must be initialized.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>Module</td>
|
|
<td class=code>module() const</td>
|
|
<td>This module as a Module.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>add_varargs_method (char *name, method_varargs_function_t method, char *documentation="")</td>
|
|
<td>Add a method to the module.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""</td>
|
|
<td>Add a method that takes keywords</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>initialize() (protected, call from constructor)</td>
|
|
<td>Initialize the module once all methods have been added. </td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>The signatures above are:</p>
|
|
|
|
<pre>typedef Object (T::*method_varargs_function_t)( const Tuple &args );
|
|
typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws
|
|
);</pre>
|
|
|
|
<p>That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The
|
|
example below has an & in front of the name of the method; we found one compiler that
|
|
needed this.</p>
|
|
|
|
<h2>Creating a Python extension type</h2>
|
|
|
|
<p>One of the great things about Python is the way you can create your own object types
|
|
and have Python welcome them as first-class citizens. Unfortunately, part of the way you
|
|
have to do this is not great. Key to the process is the creation of a Python "type
|
|
object". All instances of this type must share a reference to this one unique type
|
|
object. The type object itself has a multitude of "slots" into which the
|
|
addresses of functions can be added in order to give the object the desired behavior. </p>
|
|
|
|
<p>Creating extension objects is of course harder since you must specify
|
|
how the object behaves and give it methods. This is shown in some detail in the example
|
|
range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never
|
|
created a Python extension before, you should read the Extension manual first and be very
|
|
familiar with Python's "special class methods". Then what follows will make more
|
|
sense.</p>
|
|
|
|
<p>The basic idea is to inherit from PythonExtension templated on your self</p>
|
|
|
|
<pre>class MyObject: public PythonExtension<MyObject> {...}</pre>
|
|
|
|
<p>As a consequence:
|
|
|
|
<ul>
|
|
<li>MyObject is a child of PyObject, so that a MyObject* is-a PyObject*. </li>
|
|
<li>A static method <cite>check(PyObject*)</cite> is created in class MyObject. This function
|
|
returns a boolean, testing whether or not the argument is in fact a pointer to an instance
|
|
of MyObject.</li>
|
|
<li>The user can connect methods of MyObject to Python so that they are methods on MyObject
|
|
objects. Each such method has the signature:<br>
|
|
Object method_name (const Tuple& args).</li>
|
|
<li>The user can override virtual methods of PythonExtension in order to set behaviors.</li>
|
|
<li>A method is created to handle the deletion of an instance if and when its reference
|
|
count goes to zero. This method ensures the calling of the class destructor ~MyObject(),
|
|
if any, and releases the memory (see below).</li>
|
|
<li>Both automatic and heap-based instances of MyObject can be created.</li>
|
|
</ul>
|
|
|
|
<h3>Sample usage of PythonExtension</h3>
|
|
|
|
<p>Here is a brief overview. You create a class that inherits from PythonExtension
|
|
templated upon itself. You override various methods from PythonExtension to implement
|
|
behaviors, such as getattr, sequence_item, etc. You can also add methods to the object
|
|
that are usable from Python using a similar scheme as for module methods above. </p>
|
|
|
|
<p>One of the consequences of inheriting from PythonExtension is that you are inheriting
|
|
from PyObject itself. So your class is-a PyObject and instances of it can be passed to the
|
|
Python C API. Note: this example uses the namespace feature of PyCXX.</p>
|
|
|
|
<p>Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement
|
|
<cite>using Py;</cite> at the top of your files.</p>
|
|
|
|
<pre>class range: public Py::PythonExtension<range> {
|
|
public:
|
|
... constructors, data, etc.
|
|
... methods not callable from Python
|
|
// initializer, see below
|
|
static void init_type();
|
|
// override functions from PythonExtension
|
|
virtual Py::Object repr();
|
|
virtual Py::Object getattr( const char *name );
|
|
|
|
virtual int sequence_length();
|
|
virtual Py::Object sequence_item( int i );
|
|
virtual Py::Object sequence_concat( const Py::Object &j );
|
|
virtual Py::Object sequence_slice( int i, int j );
|
|
|
|
// define python methods of this object
|
|
Py::Object amethod (const Py::Tuple& args);
|
|
Py::Object value (const Py::Tuple& args);
|
|
Py::Object assign (const Py::Tuple& args);
|
|
};</pre>
|
|
|
|
<p>
|
|
To initialize the type we provide a static method that we can call from some module's
|
|
initializer. We set the name, doc string, and indicate which behaviors range objects
|
|
support. Then we adds the methods.</p>
|
|
|
|
<pre>void range::init_type()
|
|
{
|
|
behaviors().name("range");
|
|
behaviors().doc("range objects: start, stop, step");
|
|
behaviors().supportRepr();
|
|
behaviors().supportGetattr();
|
|
behaviors().supportSequenceType();
|
|
|
|
add_varargs_method("amethod", &range::amethod,
|
|
"demonstrate how to document amethod");
|
|
add_varargs_method("assign", &range::assign);
|
|
add_varargs_method("value", &range::value);
|
|
}</pre>
|
|
</a>
|
|
|
|
<p>Do not forget to add the call range::init_type() to some module's init function. You will want
|
|
a method in some module that can create range objects, too.</p>
|
|
|
|
<h3>Interface to PythonExtension <T></h3>
|
|
|
|
<p>Your extension class T inherits PythonExtension<T>.</p>
|
|
|
|
<table cellspacing=0 cellpadding=3px width="95%">
|
|
<tr>
|
|
<th>Type</td>
|
|
<th>Name</td>
|
|
<th>Comment</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>virtual </td>
|
|
<td class=code>~PythonExtension<T>() </td>
|
|
<td>Destructor</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>PyTypeObject* </td>
|
|
<td class=code>type_object() const</td>
|
|
<td>Returns the object type object.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>int</td>
|
|
<td class=code>check (PyObject* p)</td>
|
|
<td>Is p a T?</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3"><strong>Protected </strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>add_varargs_method (char *name, method_keyword_function_t method, char *documentation=""</td>
|
|
<td>Add a method that takes arguments</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void </td>
|
|
<td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""</td>
|
|
<td>Add a method that takes keywords</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>static PythonType&</td>
|
|
<td class=code>behaviors()</td>
|
|
<td>The type object</td>
|
|
</tr>
|
|
<tr>
|
|
<td class=code>void</td>
|
|
<td class=code>initialize() (protected, call from constructor)</td>
|
|
<td>Initialize the module once all methods have been added. </td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>As before the signatures for the methods are Object mymethod(const Tuple&
|
|
args) and Object mykeywordmethod (const Tuple& args, const Dict& keys). In this
|
|
case, the methods must be methods of T.</p>
|
|
|
|
<p>To set the behaviors of the object you override some or all of these methods from
|
|
PythonExtension<T>:</p>
|
|
|
|
<pre> virtual int print( FILE *, int );
|
|
virtual Object getattr( const char * );
|
|
virtual int setattr( const char *, const Object & );
|
|
virtual Object getattro( const Object & );
|
|
virtual int setattro( const Object &, const Object & );
|
|
virtual int compare( const Object & );
|
|
virtual Object repr();
|
|
virtual Object str();
|
|
virtual long hash();
|
|
virtual Object call( const Object &, const Object & );
|
|
|
|
// Sequence methods
|
|
virtual int sequence_length();
|
|
virtual Object sequence_concat( const Object & );
|
|
virtual Object sequence_repeat( int );
|
|
virtual Object sequence_item( int );
|
|
virtual Object sequence_slice( int, int );
|
|
virtual int sequence_ass_item( int, const Object & );
|
|
virtual int sequence_ass_slice( int, int, const Object & );
|
|
|
|
// Mapping
|
|
virtual int mapping_length();
|
|
virtual Object mapping_subscript( const Object & );
|
|
virtual int mapping_ass_subscript( const Object &, const Object & );
|
|
|
|
// Number
|
|
virtual int number_nonzero();
|
|
virtual Object number_negative();
|
|
virtual Object number_positive();
|
|
virtual Object number_absolute();
|
|
virtual Object number_invert();
|
|
virtual Object number_int();
|
|
virtual Object number_float();
|
|
virtual Object number_long();
|
|
virtual Object number_oct();
|
|
virtual Object number_hex();
|
|
virtual Object number_add( const Object & );
|
|
virtual Object number_subtract( const Object & );
|
|
virtual Object number_multiply( const Object & );
|
|
virtual Object number_divide( const Object & );
|
|
virtual Object number_remainder( const Object & );
|
|
virtual Object number_divmod( const Object & );
|
|
virtual Object number_lshift( const Object & );
|
|
virtual Object number_rshift( const Object & );
|
|
virtual Object number_and( const Object & );
|
|
virtual Object number_xor( const Object & );
|
|
virtual Object number_or( const Object & );
|
|
virtual Object number_power( const Object &, const Object & );
|
|
|
|
// Buffer
|
|
virtual int buffer_getreadbuffer( int, void** );
|
|
virtual int buffer_getwritebuffer( int, void** );
|
|
virtual int buffer_getsegcount( int* );</pre>
|
|
|
|
<p>Note that dealloc is not one of the functions you can override. That is what your
|
|
destructor is for. As noted below, dealloc behavior is provided for you by
|
|
PythonExtension.</p>
|
|
|
|
<h3>Type initialization</h3>
|
|
|
|
<p>To initialize your type, supply a static public member function that can be called
|
|
from the extension module. In that function, obtain the PythonType object by calling
|
|
behaviors() and apply appropriate "support" methods from PythonType to turn on
|
|
the support for that behavior or set of behaviors.</p>
|
|
|
|
<pre> void supportPrint(void);
|
|
void supportGetattr(void);
|
|
void supportSetattr(void);
|
|
void supportGetattro(void);
|
|
void supportSetattro(void);
|
|
void supportCompare(void);
|
|
void supportRepr(void);
|
|
void supportStr(void);
|
|
void supportHash(void);
|
|
void supportCall(void);
|
|
|
|
void supportSequenceType(void);
|
|
void supportMappingType(void);
|
|
void supportNumberType(void);
|
|
void supportBufferType(void);</pre>
|
|
|
|
<p>Then call add_varargs_method or add_keyword_method to add any methods desired to the
|
|
object.</p>
|
|
|
|
<h3>Notes on memory management and extension objects</h3>
|
|
|
|
<p>Normal Python objects exist only on the heap. That is unfortunate, as object creation
|
|
and destruction can be relatively expensive. Class PythonExtension allows creation of both
|
|
local and heap-based objects.</p>
|
|
|
|
<p>If an extension object is created using operator new, as in:</p>
|
|
|
|
<pre>range* my_r_ref = new range(1, 20, 3)</pre>
|
|
|
|
<p>then the entity my_r_ref can be thought of as "owning" the reference created
|
|
in the new object. Thus, the object will never have a reference count of zero. If the
|
|
creator wishes to delete this object, they should either make sure the reference count is
|
|
1 and then do delete my_r_ref, or decrement the reference with Py_DECREF(my_r_ref).</p>
|
|
|
|
<p>Should my_r_ref give up ownership by being used in an Object constructor, all will
|
|
still be well. When the Object goes out of scope its destructor will be called, and that
|
|
will decrement the reference count, which in turn will trigger the special dealloc routine
|
|
that calls the destructor and deletes the pointer.</p>
|
|
|
|
<p>If the object is created with automatic scope, as in:</p>
|
|
|
|
<pre>range my_r(1, 20, 3)</pre>
|
|
|
|
<p>then my_r can be thought of as owning the reference, and when my_r goes out of scope
|
|
the object will be destroyed. Of course, care must be taken not to have kept any permanent
|
|
reference to this object. Fortunately, in the case of an exception, the C++ exception
|
|
facility will call the destructor of my_r. Naturally, care must be taken not to end up
|
|
with a dangling reference, but such objects can be created and destroyed more efficiently
|
|
than heap-based PyObjects.</p>
|
|
|
|
<h2>Putting it all together</h2>
|
|
|
|
<p>The Demo directory of the distribution contains an extensive example of how to use many
|
|
of the facilities in PyCXX. It also serves as a test routine. This test is not completely
|
|
exhaustive but does excercise much of the facility.</p>
|
|
|
|
<h2>Acknowledgment</h2>
|
|
|
|
<p>Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its
|
|
template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry
|
|
Scott as co-author. -- Paul Dubois</p>
|
|
|
|
</body>
|
|
</html>
|