mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
Add documentation
[SVN r7959]
This commit is contained in:
176
comparisons.html
Normal file
176
comparisons.html
Normal file
@@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<title>
|
||||
Comparisons with Other Systems
|
||||
</title>
|
||||
<div>
|
||||
<h1>
|
||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Comparisons with
|
||||
Other Systems
|
||||
</h1>
|
||||
|
||||
<h2>CXX</h2>
|
||||
<p>
|
||||
Like py_cpp, <a href="http://cxx.sourceforge.net/">CXX</a> attempts to
|
||||
provide a C++-oriented interface to Python. In most cases, like py_cpp,
|
||||
it relieves the user from worrying about reference-counts. As far as I
|
||||
can tell, there is no support for subclassing C++ extension types in
|
||||
Python. An even more-significant difference is that a user's C++ code is
|
||||
still basically "dealing with Python objects", though they are wrapped
|
||||
in C++ classes. This means such jobs as argument parsing and conversion
|
||||
are still left to be done explicitly by the user. This is not entirely a
|
||||
bad thing, as you can do some Pythonic things with CXX (e.g. variable
|
||||
and keyword arguments) that I haven't yet figured out how to enable with
|
||||
py_cpp. As far as I can tell, also CXX enables one to write what is
|
||||
essentially idiomatic Python code in C++, manipulating Python objects
|
||||
through the same fully-generic interfaces we use in Python. That use is
|
||||
also supported (less-well) by the py_cpp object wrappers. <a
|
||||
href="mailto:dubois1@llnl.gov">Paul F. Dubois</a>, the CXX maintainer,
|
||||
has told me that what I've described is only half of the picture with
|
||||
CXX, but I never understood his explanation well-enough to fill in the
|
||||
other half. I hope that you, dear reader, may be able to help me
|
||||
complete my comparitive analysis of CXX.
|
||||
|
||||
|
||||
<h2>SWIG</h2>
|
||||
<p>
|
||||
<a href= "http://www.swig.org/">SWIG</a> is an impressively mature tool
|
||||
for exporting an existing ANSI 'C' interface into various scripting
|
||||
languages. Swig relies on a parser to read your source code and produce
|
||||
additional source code files which can be compiled into a Python (or
|
||||
Perl or Tcl) extension module. It has been successfully used to create
|
||||
many Python extension modules. Like py_cpp, SWIG is trying to allow an
|
||||
existing interface to be wrapped with little or no change to the
|
||||
existing code. The documentation says "SWIG parses a form of ANSI C
|
||||
syntax that has been extended with a number of special directives. As a
|
||||
result, interfaces are usually built by grabbing a header file and
|
||||
tweaking it a little bit." For C++ interfaces, the tweaking has often
|
||||
proven to amount to more than just a little bit. One user
|
||||
writes:<blockquote> "The problem with swig (when I used it) is that it
|
||||
couldnt handle templates, didnt do func overloading properly etc. For
|
||||
ANSI C libraries this was fine. But for usual C++ code this was a
|
||||
problem. Simple things work. But for anything very complicated (or
|
||||
realistic), one had to write code by hand. I believe py_cpp doesnt have
|
||||
this problem[sic]... IMHO overloaded functions are very important to
|
||||
wrap correctly."<br><i>-Prabhu Ramachandran</i>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
By contrast, py_cpp doesn't attempt to parse C++ - the problem is simply
|
||||
too complex to do correctly. Technically, one does write code by hand to
|
||||
use py_cpp. The goal, however, has been to make that code nearly as
|
||||
simple as listing the names of the classes and member functions you want
|
||||
to expose in Python.
|
||||
|
||||
<h2>SIP</h2>
|
||||
<p>
|
||||
<a
|
||||
href="http://www.thekompany.com/projects/pykde/background.php3?dhtml_ok=1">SIP</a>
|
||||
is a system similar to SWIG, though seemingly more
|
||||
C++-oriented. The author says that like py_cpp, SIP supports overriding
|
||||
extension class member functions in Python subclasses. It appears to
|
||||
have been designed specifically to directly support some features of
|
||||
PyQt/PyKDE, which is its primary client. Documentation is almost
|
||||
entirely missing at the time of this writing, so a detailed comparison
|
||||
is difficult.
|
||||
|
||||
<h2>ILU</h2>
|
||||
<p>
|
||||
<a
|
||||
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual">ILU</a>
|
||||
is a very ambitious project which tries to describe a module's interface
|
||||
(types and functions) in terms of an <a
|
||||
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual/manual_2.html">Interface
|
||||
Specification Language</a> (ISL) so that it can be uniformly interfaced
|
||||
to a wide range of computer languages, including Common Lisp, C++, C,
|
||||
Modula-3, and Python. ILU can parse the ISL to generate a C++ language
|
||||
header file describing the interface, of which the user is expected to
|
||||
provide an implementation. Unlike py_cpp, this means that the system
|
||||
imposes implementation details on your C++ code at the deepest level. It
|
||||
is worth noting that some of the C++ names generated by ILU are supposed
|
||||
to be reserved to the C++ implementation. It is unclear from the
|
||||
documentation whether ILU supports overriding C++ virtual functions in Python.
|
||||
|
||||
<h2>Zope ExtensionClasses</h2>
|
||||
<p>
|
||||
<a href="http:http://www.digicool.com/releases/ExtensionClass">
|
||||
ExtensionClasses in Zope</a> use the same underlying mechanism as py_cpp
|
||||
to support subclassing of extension types in Python, including
|
||||
multiple-inheritance. Both systems rely on the same "<a
|
||||
href="http://www.python.org/workshops/1994-11/BuiltInClasses/Welcome.html">Don
|
||||
Beaudry Hack</a>" that also inspired Don's MESS System.
|
||||
<p>
|
||||
The major differences are:
|
||||
<ul>
|
||||
<li>
|
||||
py_cpp lifts the burden on the user to parse and convert function
|
||||
argument types. Zope provides no such facility.
|
||||
<li>
|
||||
py_cpp lifts the burden on the user to maintain Python
|
||||
reference-counts.
|
||||
<li>
|
||||
py_cpp supports function overloading; Zope does not.
|
||||
<li>
|
||||
py_cpp supplies a simple mechanism for exposing read-only and
|
||||
read/write access to data members of the wrapped C++ type as Python
|
||||
attributes.
|
||||
<li>
|
||||
Writing a Zope ExtensionClass is significantly more complex than
|
||||
exposing a C++ class to python using py_cpp (mostly a summary of the
|
||||
previous 4 items). <a href=
|
||||
"http://www.digicool.com/releases/ExtensionClass/MultiMapping.html">A
|
||||
Zope Example</a> illustrates the differences.
|
||||
<li>
|
||||
Zope's ExtensionClasses are specifically motivated by "the need for a
|
||||
C-based persistence mechanism". Py_cpp's are motivated by the desire
|
||||
to simply reflect a C++ API into Python with as little modification as
|
||||
possible.
|
||||
<li>
|
||||
Thus, Zope's ExtensionClasses support pickling. Currently py_cpp
|
||||
ExtensionClasses do not.
|
||||
<li>
|
||||
The following Zope restriction does not apply to py_cpp: "At most one
|
||||
base extension direct or indirect super class may define C data
|
||||
members. If an extension subclass inherits from multiple base
|
||||
extension classes, then all but one must be mix-in classes that
|
||||
provide extension methods but no data."
|
||||
<li>
|
||||
Zope's Extension SubClasses admit multiple-inheritance from both Zope
|
||||
ExtensionClasses <i>and</i> Python classes. This capability is currently
|
||||
not available in py_cpp.
|
||||
<li>
|
||||
Zope supplies the standard special Python class attributes __doc__,
|
||||
__name__, __bases__, __dict__, and __module__ on its
|
||||
ExtensionClasses; py_cpp does not (coming soon)
|
||||
<li>
|
||||
Zope supplies some creative but esoteric idioms such as <a href=
|
||||
"http://www.digicool.com/releases/ExtensionClass/Acquisition.html">
|
||||
Acquisition</a>.
|
||||
<li>
|
||||
Zope's ComputedAttribute support is designed to be used from Python.
|
||||
The analogous feature of py_cp is designed to be used from C++ (I
|
||||
make no claims that the py_cpp mechanism is more useful than the Zope
|
||||
mechanism in this case)
|
||||
</ul>
|
||||
<p>
|
||||
Also, the Zope docs say: "The first superclass listed in the class
|
||||
statement defining an extension subclass must be either a base
|
||||
extension class or an extension subclass. This restriction will be
|
||||
removed in Python-1.5." I believe that this promise was made
|
||||
prematurely. I have looked at the Python 1.5.2 source code and I don't
|
||||
believe it is possible to deliver on it.
|
||||
<p>
|
||||
Previous: <a href="extending.html">A Brief Introduction to writing Python Extension Modules</a>
|
||||
Next: <a href="example1.html">A Simple Example Using py_cpp</a>
|
||||
Up: <a href="py_cpp.html">Top</a>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability
|
||||
for any purpose.
|
||||
<p>
|
||||
Updated: Oct 15, 2000
|
||||
</div>
|
||||
|
||||
127
example1.html
Normal file
127
example1.html
Normal file
@@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<title>
|
||||
A Simple Example Using py_cpp
|
||||
</title>
|
||||
<div>
|
||||
<h1>
|
||||
<img width="277" height="86" id="_x0000_i1025" src="c++boost.gif" alt=
|
||||
"c++boost.gif (8819 bytes)">
|
||||
</h1>
|
||||
<h1>
|
||||
A Simple Example Using py_cpp
|
||||
</h1>
|
||||
<p>
|
||||
Suppose we have the following C++ API which we want to expose in
|
||||
Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
namespace hello {
|
||||
class world
|
||||
{
|
||||
public:
|
||||
world(int);
|
||||
~world();
|
||||
const char* get() const { return "hi, world"; }
|
||||
...
|
||||
};
|
||||
void length(const world& x) { return std::strlen(x.get()); }
|
||||
}
|
||||
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Here is the C++ code for a python module called <code>hello</code>
|
||||
which exposes the API using py_cpp:
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <py_cpp/class_wrapper.h>
|
||||
// Python requires an exported function called init<module-name> in every
|
||||
// extension module. This is where we build the module contents.
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void inithello()
|
||||
{
|
||||
try
|
||||
{
|
||||
// create an object representing this extension module
|
||||
py::Module hello("hello");
|
||||
// Create the Python type object for our extension class
|
||||
py::ClassWrapper<hello::world> world_class(hello, "world");
|
||||
// Add the __init__ function
|
||||
world_class.def(py::Constructor<int>());
|
||||
// Add a regular member function
|
||||
world_class.def(&hello::world::get, "get");
|
||||
// Add a regular function to the module
|
||||
hello.def(hello::length, "length");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
py::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
// Win32 DLL boilerplate
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif // _WIN32
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
That's it! If we build this shared library and put it on our <code>
|
||||
PYTHONPATH</code> we can now access our C++ class and function from
|
||||
Python.
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> import hello
|
||||
>>> hi_world = hello.world(3)
|
||||
>>> hi_world.get()
|
||||
'hi, world'
|
||||
>>> hello.length(hi_world)
|
||||
9
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
We can even make a subclass of <code>hello.world</code>:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> class my_subclass(hello.world):
|
||||
... def get(self):
|
||||
... return 'hello, world'
|
||||
...
|
||||
>>> y = my_subclass(4)
|
||||
>>> y.get()
|
||||
'hello, world'
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Pretty cool! You can't do that with an ordinary Python extension type!
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> hello.length(y)
|
||||
9
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Of course, you may now have a slightly empty feeling in the pit of
|
||||
your little pythonic stomach. Perhaps you feel your subclass deserves
|
||||
to have a <code>length()</code> of <code>12</code>? If so, <a href=
|
||||
"overriding.html">read on</a>...
|
||||
<p>
|
||||
Previous: <a href="comparisons.html">Comparisons with other systems</a> Next: <a href="overriding.html">Overridable virtual functions</a> Up:
|
||||
<a href="py_cpp.html">Top</a>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability
|
||||
for any purpose.
|
||||
<p>
|
||||
Updated: Oct 15, 2000
|
||||
</div>
|
||||
|
||||
73
extending.html
Normal file
73
extending.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>
|
||||
A Brief Introduction to writing Python extension modules
|
||||
</title>
|
||||
<h1>
|
||||
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||
width="277" height="86">
|
||||
</h1>
|
||||
<h1>
|
||||
A Brief Introduction to writing Python extension modules
|
||||
</h1>
|
||||
<p>
|
||||
Interfacing any language to Python involves building a module which can
|
||||
be loaded by the Python interpreter, but which isn't written in Python.
|
||||
This is known as an <em>extension module</em>. Many of the <a href=
|
||||
"http://www.python.org/doc/current/lib/lib.html">built-in Python
|
||||
libraries</a> are constructed in 'C' this way; Python even supplies its
|
||||
<a href="http://www.python.org/doc/current/lib/types.html">fundamental
|
||||
types</a> using the same mechanism. An extension module can be statically
|
||||
linked with the Python interpreter, but it more commonly resides in a
|
||||
shared library or DLL.
|
||||
<p>
|
||||
As you can see from <a href=
|
||||
"http://www.python.org/doc/current/ext/ext.html"> The Python Extending
|
||||
and Embedding Tutorial</a>, writing an extension module normally means
|
||||
worrying about
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://www.python.org/doc/current/ext/refcounts.html">
|
||||
maintaining reference counts</a>
|
||||
<li>
|
||||
<a href="http://www.python.org/doc/current/ext/callingPython.html"> how
|
||||
to call back into Python</a>
|
||||
<li>
|
||||
<a href="http://www.python.org/doc/current/ext/parseTuple.html">
|
||||
function argument parsing and typechecking</a>
|
||||
</ul>
|
||||
This last item typically occupies a great deal of code in an extension
|
||||
module. Remember that Python is a completely dynamic language. A callable
|
||||
object receives its arguments in a tuple; it is up to that object to
|
||||
extract those arguments from the tuple, check their types, and raise
|
||||
appropriate exceptions. There are numerous other tedious details that need
|
||||
to be managed; too many to mention here. Py_cpp is designed to lift most of
|
||||
that burden.<br>
|
||||
<br>
|
||||
|
||||
<p>
|
||||
Another obstacle that most people run into eventually when extending
|
||||
Python is that there's no way to make a true Python class in an extension
|
||||
module. The typical solution is to create a new Python type in the
|
||||
extension module, and then write an additional module in 100% Python. The
|
||||
Python module defines a Python class which dispatches to an instance of
|
||||
the extension type, which it contains. This allows users to write
|
||||
subclasses of the class in the Python module, almost as though they were
|
||||
sublcassing the extension type. Aside from being tedious, it's not really
|
||||
the same as having a true class, because there's no way for the user to
|
||||
override a method of the extension type which is called from the
|
||||
extension module. Py_cpp solves this problem by taking advantage of <a
|
||||
href="http://www.python.org/doc/essays/metaclasses/">Python's metaclass
|
||||
feature</a> to provide objects which look, walk, and hiss almost exactly
|
||||
like regular Python classes. Py_cpp classes are actually cleaner than
|
||||
Python classes in some subtle ways; a more detailed discussion will
|
||||
follow (someday).</p>
|
||||
<p>Next: <a href="comparisons.html">Comparisons with Other Systems</a> Up: <a
|
||||
href="py_cpp.html">Top</a> </p>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.</p>
|
||||
|
||||
139
overloading.html
Normal file
139
overloading.html
Normal file
@@ -0,0 +1,139 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<title>
|
||||
Function Overloading
|
||||
</title>
|
||||
<div>
|
||||
<h1>
|
||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Function Overloading
|
||||
</h1>
|
||||
|
||||
<h2>An Example</h2>
|
||||
<p>
|
||||
To expose overloaded functions in Python, simply <code>def()</code> each
|
||||
one with the same Python name:
|
||||
<blockquote>
|
||||
<pre>
|
||||
inline int f1() { return 3; }
|
||||
inline int f2(int x) { return x + 1; }
|
||||
|
||||
class X {
|
||||
public:
|
||||
X() : m_value(0) {}
|
||||
X(int n) : m_value(n) {}
|
||||
int value() const { return m_value; }
|
||||
void value(int v) { m_value = v; }
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
...
|
||||
|
||||
void initoverload_demo()
|
||||
{
|
||||
try
|
||||
{
|
||||
py::Module overload_demo("overload_demo");
|
||||
// Overloaded functions at module scope
|
||||
overload_demo.def(f1, "f");
|
||||
overload_demo.def(f2, "f");
|
||||
|
||||
py::ClassWrapper<X> x_class(overload_demo, "X");
|
||||
// Overloaded constructors
|
||||
x_class.def(py::Constructor<>());
|
||||
x_class.def(py::Constructor<int>());
|
||||
|
||||
// Overloaded member functions
|
||||
x_class.def((int (X::*)() const)&X::value, "value");
|
||||
x_class.def((void (X::*)(int))&X::value, "value");
|
||||
...
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
Now in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> from overload_demo import *
|
||||
>>> x0 = X()
|
||||
>>> x1 = X(1)
|
||||
>>> x0.value()
|
||||
0
|
||||
>>> x1.value()
|
||||
1
|
||||
>>> x0.value(3)
|
||||
>>> x0.value()
|
||||
3
|
||||
>>> X('hello')
|
||||
TypeError: No overloaded functions match (X, string). Candidates are:
|
||||
void (*)()
|
||||
void (*)(int)
|
||||
>>> f()
|
||||
3
|
||||
>>> f(4)
|
||||
5
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Discussion</h2>
|
||||
<p>
|
||||
Notice that overloading in the Python module was produced three ways:<ol>
|
||||
<li>by combining the non-overloaded C++ functions <code>int f1()</code>
|
||||
and <code>int f2(int)</code> and exposing them as <code>f</code> in Python.
|
||||
<li>by exposing the overloaded constructors of <code>class X</code>
|
||||
<li>by exposing the overloaded member functions <code>X::value</code>.
|
||||
</ol>
|
||||
<p>
|
||||
Techniques 1. and 3. above are really alternatives. In case 3, you need
|
||||
to form a pointer to each of the overloaded functions. The casting
|
||||
syntax shown above is one way to do that in C++. Case 1 does not require
|
||||
complicated-looking casts, but may not be viable if you can't change
|
||||
your C++ interface. N.B. There's really nothing unsafe about casting an
|
||||
overloaded (member) function address this way: the compiler won't let
|
||||
you write it at all unless you get it right.
|
||||
|
||||
<h2>An Alternative to Casting</h2>
|
||||
<p>
|
||||
This approach is not neccessarily better, but may be preferable for some
|
||||
people who have trouble writing out the types of (member) function
|
||||
pointers or simply prefer to avoid all casts as a matter of principle:
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Forwarding functions for X::value
|
||||
inline void set_x_value(X& self, int v) { self.value(v); }
|
||||
inline int get_x_value(X& self) { return self.value(); }
|
||||
...
|
||||
// Overloaded member functions
|
||||
x_class.def(set_x_value, "value");
|
||||
x_class.def(get_x_value, "value");
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>Here we are taking advantage of the ability to expose C++ functions at
|
||||
namespace scope functions as Python member functions.
|
||||
|
||||
<h2>Overload Resolution</h2>
|
||||
<p>
|
||||
The function overload resolution mechanism in py_cpp works as
|
||||
follows:<ul>
|
||||
<li>Attribute lookup for extension classes proceeds in the usual way. When a
|
||||
class is found which has a matching attribute, only functions overloaded
|
||||
in the context of that class are candidates for overload resolution.
|
||||
<li>Within a name-space context (extension class or module), overloaded
|
||||
functions are tried in the same order they were
|
||||
<code>def()</code>ed. The first function whose signature can be made to
|
||||
match each argument passed is the one which is ultimately called.
|
||||
</ul>
|
||||
<p>
|
||||
Prev: <a href="overloading.html">Function Overloading</a>
|
||||
Next: <a href="under-the-hoold.html">A Peek Under the Hood</a>
|
||||
Up: <a href="py_cpp.html">Top</a>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability
|
||||
for any purpose.
|
||||
<p>
|
||||
Updated: Oct 15, 2000
|
||||
</div>
|
||||
|
||||
175
overriding.html
Normal file
175
overriding.html
Normal file
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>
|
||||
Overridable Virtual Functions
|
||||
</title>
|
||||
<h1>
|
||||
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||
width="277" height="86">
|
||||
</h1>
|
||||
<h1>
|
||||
Overridable Virtual Functions
|
||||
</h1>
|
||||
<p>
|
||||
In the <a href="example1.html">previous example</a> we exposed a simple
|
||||
C++ class in Python and showed that we could write a subclass. We even
|
||||
redefined one of the functions in our derived class. Now we will learn
|
||||
how to make the function <em>behave virtually</em>. Of course, the first
|
||||
step if we want it to act like a virtual function when called from our
|
||||
C++ code, is to <em>make</em> it virtual:
|
||||
<blockquote>
|
||||
<pre>
|
||||
class world
|
||||
{
|
||||
...
|
||||
<strong>virtual</strong> const char* get() const { return "hi, world"; }
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Then we'll need a derived class<a href="#why_derived">*</a> to help us
|
||||
dispatch the call to Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
struct world_callback : hello::world
|
||||
{
|
||||
// The first argument must by a PyObject* (the corresponding Python object)
|
||||
// The rest of the argument list should match the base class constructor
|
||||
world_callback(PyObject* self, int x)
|
||||
: world(x), // dispatch to base object
|
||||
m_self(self) {} // hang onto the Python object
|
||||
|
||||
// Dispatch the call to Python
|
||||
const char* get() const
|
||||
{
|
||||
// Any function arguments would go at the end of the argument list
|
||||
// The return type is a template parameter
|
||||
return py::Callback<const char*>::call_method(m_self, "get");
|
||||
}
|
||||
|
||||
// <a name=
|
||||
"default_implementation">Something Python can call</a> in case there is no override of get()
|
||||
const char* default_get() const
|
||||
{ return this->hello::world::get(); }
|
||||
private:
|
||||
PyObject* m_self; // A way to hold onto the Python object
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Finally, we add <code>world_callback</code> to the <code>
|
||||
ClassWrapper<></code> declaration in our module initialization
|
||||
function:
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Create the <a name=
|
||||
"world_class">Python type object</a> for our extension class
|
||||
py::ClassWrapper<hello::world<strong>,world_callback></strong> world_class(hello, "world");
|
||||
...
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
...and when we define the function, we must tell py_cpp about the default
|
||||
implementation:
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Add a virtual member function
|
||||
world_class.def(&hello::world::get, "get", &world_callback::default_get);
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Now our subclass of <code>hello.world</code> behaves as expected:
|
||||
<p>
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> class my_subclass(hello.world):
|
||||
... def get(self):
|
||||
... return 'hello, world'
|
||||
...
|
||||
>>> hello.length(my_subclass())
|
||||
12
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
<a name="why_derived">*</a>You may ask, "Why do we need this derived
|
||||
class? This could have been designed so that everything gets done right
|
||||
inside of <code>hello::world</code>." One of the goals of py_cpp is to be
|
||||
minimally intrusive on an existing C++ design. In principle, it should be
|
||||
possible to expose the interface for a 3rd party library without changing
|
||||
it.
|
||||
<h2>
|
||||
Pure Virtual Functions
|
||||
</h2>
|
||||
<p>
|
||||
A pure virtual function with no implementation is actually a lot easier
|
||||
to deal with than a virtual function with a default implementation. First
|
||||
of all, you obviously don't need to <a href="#default_implementation">
|
||||
supply a default implementation</a>. Secondly, you don't need to call
|
||||
<code>def()</code> on the <code>ExtensionClass<></code> instance
|
||||
for the virtual function. In fact, you wouldn't <em>want</em> to: if the
|
||||
corresponding attribute on the Python class stays undefined, you'll get
|
||||
an <code>AttributeError</code> in Python when you try to call the
|
||||
function, indicating that it should have been implemented. For example:
|
||||
<blockquote>
|
||||
<pre>
|
||||
struct baz
|
||||
{
|
||||
<strong>virtual</strong> void pure(int) = 0;
|
||||
};
|
||||
|
||||
struct baz_callback
|
||||
{
|
||||
void pure(int x) { py::Callback<void>::call_method(m_self, "pure", x); }
|
||||
};
|
||||
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
initfoobar()
|
||||
{
|
||||
try
|
||||
{
|
||||
py::Module foobar("foobar");
|
||||
py::ClassWrapper<baz,baz_callback> baz_class("baz");
|
||||
baz_class.def(&baz::pure, "pure");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
py::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Now in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> from foobar import baz
|
||||
>>> x = baz()
|
||||
>>> x.pure()
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: pure
|
||||
>>> class mumble(baz):
|
||||
... def pure(self, z): pass
|
||||
...
|
||||
>>> y = mumble()
|
||||
>>> y.pure()
|
||||
>>>
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Prev: <a href="example1.html">A Simple Example Using py_cpp</a> Next: <a
|
||||
href="under-the-hood.html">A Peek Under the Hood</a> Up: <a href=
|
||||
"py_cpp.html">Top</a>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.
|
||||
<p>
|
||||
Updated: Sept 30, 2000
|
||||
|
||||
120
py_cpp.html
Normal file
120
py_cpp.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>
|
||||
py_cpp Python/C++ binding documentation
|
||||
</title>
|
||||
<h1>
|
||||
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277"
|
||||
align="center" height="86"> py_cpp<a href="#naming_contest">*</a>
|
||||
</h1>
|
||||
<p>
|
||||
Py_cpp is a system for quickly and easily interfacing C++ code with <a
|
||||
href="http:www.python.org">Python</a> such that the Python interface is
|
||||
very similar to the C++ interface. It is designed to be minimally
|
||||
intrusive on your C++ design. In most cases, you should not have to alter
|
||||
your C++ classes in any way in order to use them with py_cpp. The system
|
||||
<em>should</em> simply "reflect" your C++ classes and functions into
|
||||
Python.
|
||||
<p>
|
||||
The source code for py_cpp, including a MSVC demo project is available
|
||||
<a href="py_cpp_20001013.zip">here</a>. It has been tested against Python
|
||||
1.5.2 with GCC 2.95.2, Metrowerks CodeWarrior Pro6 and with Microsoft
|
||||
Visual C++ 6 sp4 using both the <a href="http://www.stlport.org">
|
||||
STLport</a> standard library implementation <em>and</em> the library
|
||||
implementation which ships with the compiler. It has also been tested
|
||||
against Python 2.0c1 with an unknown version of MSVC++ by Alex Martelli.
|
||||
Py_cpp requires the <a href="http://www.boost.org">Boost</a> libraries,
|
||||
and is currently under formal review on <a href=
|
||||
"http://www.egroups.com/list/boost">the boost mailing list</a> for
|
||||
acceptance into boost.
|
||||
<p>
|
||||
py_cpp was originally written by David Abrahams. Ullrich Koethe supplied
|
||||
an early version of the overloading support and wrote the support for
|
||||
implicit conversions of arguments that have a C++ inheritance
|
||||
relationship. Alex Martelli supplied the first tests against Python 2.0.
|
||||
The members of the boost mailing list and the Python community supplied
|
||||
invaluable early feedback. The development of py_cpp wouldn't have been
|
||||
possible without the generous support of Dragon Systems/Lernout and
|
||||
Hauspie, Inc.
|
||||
<h2>
|
||||
Table of Contents
|
||||
</h2>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="extending.html">A Brief Introduction to writing Python
|
||||
extension modules</a>
|
||||
<li>
|
||||
<a href="comparisons.html">Comparisons between py_cpp and other systems
|
||||
for extending Python</a>
|
||||
<li>
|
||||
<a href="example1.html">A Simple Example Using py_cpp</a>
|
||||
<li>
|
||||
<a href="overriding.html">Overridable Virtual Functions</a>
|
||||
<li>
|
||||
<a href="overloading.html">Function Overloading</a>
|
||||
<li>
|
||||
<a href="under-the-hood.html">A Peek Under the Hood</a>
|
||||
</ol>
|
||||
<p>
|
||||
More sophisticated examples, including examples which demonstrate that
|
||||
these ExtensionClasses support some of Python's "special" member
|
||||
functions (e.g. <code>__getattr__(self, name)</code>), are given in
|
||||
<code>extclass_demo.cpp</code>, <code> extclass_demo.h</code>, and <code>
|
||||
test_extclass.py</code> in the <a href="py_cpp.tgz">source code
|
||||
archive</a>. There's much more here, and much more documentation to
|
||||
come...
|
||||
<p>
|
||||
Questions should be directed to <a href=
|
||||
"http://www.egroups.com/list/boost">the boost mailing list</a> or to <a
|
||||
href="mailto:abrahams@mediaone.net"> David Abrahams</a>, the primary
|
||||
author and maintainer.
|
||||
<h3>
|
||||
Naming Contest
|
||||
</h3>
|
||||
<p>
|
||||
Yes, I know py_cpp is a lousy name. Problem is, the best names my puny
|
||||
imagination can muster (IDLE and GRAIL) are taken, so I'm holding a
|
||||
naming contest. First prize? You get to pick the name<0.2wink> and
|
||||
you will be credited in the documentation. Names that have been suggested
|
||||
so far include:
|
||||
<ul>
|
||||
<li>
|
||||
Py++
|
||||
<li>
|
||||
Python++
|
||||
<li>
|
||||
Coil
|
||||
<li>
|
||||
SnakeSkin
|
||||
<li>
|
||||
CCCP - <strong>C</strong>onvert <strong>C</strong>++ <strong>
|
||||
C</strong>lasses to <strong>P</strong>ython
|
||||
<li>
|
||||
C<sup>3</sup>PO - <strong>C</strong>onvert <strong>C</strong>++
|
||||
<strong>C</strong>lasses to <strong>P</strong>ython <strong>
|
||||
O</strong>bjects
|
||||
<li>
|
||||
PALIN - <strong>P</strong>ython <strong>
|
||||
A</strong>ugmented-<strong>L</strong>anguage <strong>
|
||||
IN</strong>tegration
|
||||
<li>
|
||||
C-thru
|
||||
<li>
|
||||
SeamlessC
|
||||
<li>
|
||||
BorderCrossing
|
||||
</ul>
|
||||
Please <a href="http://www.egroups.com/list/boost">post</a> or send <a
|
||||
href="http:mailto:abrahams@mediaone.net">me</a> your suggestions!<br>
|
||||
<br>
|
||||
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.
|
||||
<p>
|
||||
Updated: Oct 15, 2000
|
||||
|
||||
58
under-the-hood.html
Normal file
58
under-the-hood.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>
|
||||
A Peek Under the Hood
|
||||
</title>
|
||||
<h1>
|
||||
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||
width="277" height="86">
|
||||
</h1>
|
||||
<h1>
|
||||
A Peek Under the Hood
|
||||
</h1>
|
||||
<p>
|
||||
<code> ExtensionClass<T></code> is a subclass of <code>
|
||||
PyTypeObject</code>, the <code> struct</code> which Python's 'C' API uses
|
||||
to describe a type. <a href="example1.html#world_class">An instance of
|
||||
the <code>ExtensionClass<></code></a> becomes the Python type
|
||||
object corresponding to <code>hello::world</code>. When we <a href=
|
||||
"example1.html#add_world_class">add it to the module</a> it goes into the
|
||||
module's dictionary to be looked up under the name "world".
|
||||
<p>
|
||||
Py_cpp uses C++'s template argument deduction mechanism to determine the
|
||||
types of arguments to functions (except constructors, for which we must
|
||||
<a href="example1.html#Constructor_example">provide an argument list</a>
|
||||
because they can't be named in C++). Then, it calls the appropriate
|
||||
overloaded functions <code>PyObject*
|
||||
to_python(</code><em>S</em><code>)</code> and <em>
|
||||
S'</em><code>from_python(PyObject*,
|
||||
Type<</code><em>S</em><code>>)</code> which convert between any C++
|
||||
type <em>S</em> and a <code>PyObject*</code>, the type which represents a
|
||||
reference to any Python object in its 'C' API. The <a href=
|
||||
"example1.html#world_class"><code>ExtensionClass<T></code></a>
|
||||
template defines a whole raft of these conversions (for <code>T, T*,
|
||||
T&, std::auto_ptr<T></code>, etc.), using the same inline
|
||||
friend function technique employed by <a href=
|
||||
"http://www.boost.org/libs/utility/operators.htm">the boost operators
|
||||
library</a>.
|
||||
<p>
|
||||
Because the <code>to_python</code> and <code>from_python</code> functions
|
||||
for a user-defined class are defined by <code>
|
||||
ExtensionClass<T></code>, it is important that an instantiation of
|
||||
<code> ExtensionClass<T></code> is visible to any code which wraps
|
||||
a C++ function with a <code>T, T*, const T&</code>, etc. parameter or
|
||||
return value. In particular, you may want to create all of the classes at
|
||||
the top of your module's init function, then <code>def</code> the member
|
||||
functions later to avoid problems with inter-class dependencies.
|
||||
<p>
|
||||
Previous: <a href="overriding.html">Function Overloading</a> Up: <a
|
||||
href="py_cpp.html">Top</a>
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.
|
||||
<p>
|
||||
Updated: Sept 30, 2000
|
||||
|
||||
Reference in New Issue
Block a user