2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-26 18:52:26 +00:00

This commit was manufactured by cvs2svn to create tag

'Version_1_21_2'.

[SVN r9983]
This commit is contained in:
nobody
2001-04-25 14:10:57 +00:00
parent 9b602d16b4
commit 718adad485
95 changed files with 8389 additions and 923 deletions

View File

@@ -1,212 +0,0 @@
<!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>
The source code for py_cpp, including a MSVC demo project is available <a
href="py_cpp_20001106.zip">here</a>.
<h2>Synopsis</h2>
<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 &ldquo;reflect&rdquo; your C++ classes and functions into
Python. The major features of py_cpp include support for:
<ul>
<li><a href="inheritance.hml">Subclassing extension types in Python</a>
<li><a href="overriding.html">Overriding virtual functions in Python</a>
<li><a href="overloading.html">[Member] function Overloading</a>
<li><a href="special.html#numeric_auto">Automatic wrapping of numeric operators</a>
</ul>
among others.
<h2>Supported Platforms</h2>
<p>py_cpp has been tested in the following configurations:
<ul>
<li>Against Python 1.5.2 using the following compiler/library:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>/<a
href="http://www.stlport.org">STLport 4.0</a>
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a> [by <a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich
Koethe</a>]
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a>/<a href="http://www.stlport.org">STLport 4.0</a>
<li>Compaq C++ V6.2-024 for Digital UNIX V5.0 Rev. 910 (an <a
href="http://www.edg.com/">EDG</a>-based compiler) with <a
href="http://www.stlport.org/beta.html">STLport-4.1b3</a> [by <a
href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve</a>]
<li>An upcoming release of <a href="http://www.metrowerks.com/products/windows/">Metrowerks CodeWarrior
Pro6 for Windows</a> (the first release has a bug that's fatal to py_cpp)
</ul>
<br>
<li>Against Python 2.0 using the following compiler/library combinations:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a> [by
<a href="mailto:aleaxit@yahoo.com">Alex Martelli</a>]
</ul>
</ul>
<p>Py_cpp requires the <a href="http://www.boost.org">boost</a> libraries, and is
has been accepted for inclusion into the boost libraries pending &ldquo;boostification&ldquo;
(completion of the documentation, change in some naming conventions and
resolution of some namespace issues).
<h2>Credits</h2>
<ul>
<li><a href="mailto:abrahams@mediaone.net">David Abrahams</a> originated
and wrote py_cpp.
<li><a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich Koethe</a>
had independently developed a similar system. When he discovered py_cpp,
he generously contributed countless hours of coding and much insight into
improving it. He is responsible for an early version of the support for <a
href="overloading.html">function overloading</a> and wrote the support for
<a href="inheritance.html#implicit_conversion">reflecting C++ inheritance
relationships</a>. He has helped to improve error-reporting from both
Python and C++, and has designed an extremely easy-to-use way of
exposing <a href="special.html#numeric">numeric operators</a>, including
a way to avoid explicit coercion by means of overloading.
<li>The members of the boost mailing list and the Python community supplied
invaluable early feedback. In particular, Ron Clarke, Mark Evans, Anton
Gluck, Ralf W. Grosse-Kunstleve, Prabhu Ramachandran, and Barry Scott took
the brave step of trying to use py_cpp while it was still in early stages
of development.
<li>The development of py_cpp wouldn't have been
possible without the generous support of <a href="http://www.dragonsys.com/">Dragon Systems/Lernout and
Hauspie, Inc</a> who supported its development as an open-source project.
</ul>
<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="inheritance.html">Inheritance</a>
<li><a href="special.html">Special Method and Operator Support</a>
<li><a href="under-the-hood.html">A Peek Under the Hood</a>
<li><a href="building.html">Building a Module with Py_cpp</a>
<li>Advanced Topics
<ol>
<li>class_builder&lt;&gt;
<li><a href="enums.html">enums</a>
<li>References
<li><a href="pointers.html">Pointers and Smart Pointers</a>
<li>Built-in Python Types
<li>Other Extension Types
<li>Templates
</ol>
</ol>
<p>
More sophisticated examples 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>.
<h2>Naming Contest</h2>
<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&lt;0.2wink&gt; 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 - <b>C</b>onvert <b>C</b>++ <b>
C</b>lasses to <b>P</b>ython
<li>
C<sup>3</sup>PO - <b>C</b>onvert <b>C</b>++
<b>C</b>lasses to <b>P</b>ython <b>
O</b>bjects
<li>
PALIN - <b>P</b>ython <b>
A</b>ugmented-<b>L</b>anguage <b>
IN</b>tegration
<li>
CLEESE - <b>C</b>++ <b>L</b>anguage <b>E</b>xtension <b>E</b>nvironment
<b>S</b>upremely <b>E</b>asy
<li>
JONES - <b>J</b>ust <b>O</b>bscenely <b>N</b>eat <b>E</b>xtension
<b>S</b>ystem
<li>
C-thru
<li>
SeamlessC
<li>
BorderCrossing
<li>
Perseus (because he solved a hairy problem involving snakes by using
reflection and was invisible most of the time).
</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>
&copy; 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 &ldquo;as is&rdquo; without
express or implied warranty, and with no claim as to its suitability for
any purpose.
<p>
Updated: Nov 26, 2000

View File

@@ -1,43 +1,180 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Building a Module with Py_cpp
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Building a Module with Py_cpp
</h1>
<p>
Right now, the only supported configuration is one in which the py_cpp
source files are statically linked with the source for your extension
module. You may first build them into a library and link it with your
extension module source, but the effect is the same as compiling all
the source files together. Some users have successfully built the
py_cpp sources into a shared library, and support for a shared library
build is planned, but not yet implemented. The py_cpp source files are:
<blockquote>
<pre>
<a href="../../../libs/python/src/extension_class.cpp">extclass.cpp</a>
<a href="../../../libs/python/src/functions.cpp">functions.cpp</a>
<a href="../../../libs/python/src/init_function.cpp">init_function.cpp</a>
<a href="../../../libs/python/src/module_builder.cpp">module.cpp</a>
<a href="../../../libs/python/src/types.cpp">newtypes.cpp</a>
<a href="../../../libs/python/src/objects.cpp">objects.cpp</a>
<a href="../../../libs/python/src/conversions.cpp">py.cpp</a>
<a href="../../../libs/python/src/classes.cpp">subclass.cpp</a>
</pre>
</blockquote>
<p>
Previous: <a href="under-the-hood.html">A Peek Under the Hood</a>
Up: <a href="index.html">Top</a>
<p>
&copy; 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 &ldquo;as
is&rdquo; without express or implied warranty, and with no claim as to
its suitability for any purpose.
<p>
Updated: Nov 26, 2000
</div>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<meta name="generator" content="HTML Tidy, see www.w3.org">
<title>Building an Extension Module</title>
<div>
<h1><img width="277" height="86" align="center" src=
"../../../c++boost.gif" alt="c++boost.gif (8819 bytes)">Building an
Extension Module</h1>
<p>The build process for Boost is currently undergoing some evolution,
and, it is to be hoped, improvement. The following facts may help:
<hr>
Makefiles for various platforms and a Visual Studio project
reside in the Boost subdirectory <tt>libs/python/build</tt>.
Build targets include:
<ul>
<li>The <tt>boost_python</tt> library for static linking with your
extension module. On the various Unices, this library will be
called <tt>libboost_python.a</tt>. When using Visual C++, the
library will be called <tt>boost_python.lib</tt>.
<p>
<li>A comprehensive test of Boost.Python features. This test builds
a Boost.Python extension module, then runs Python to import the
module, and runs a series of tests on it using <tt><a href=
"../test/doctest.py">doctest</a></tt>. Source code for the module
and tests is available in the Boost subdirectory
<tt>libs/python/test</tt>.
<p>
<li>Various examples from the Boost subdirectory
<tt>libs/python/example</tt>.
All these examples include a doctest modeled
on the comprehensive test above.
</ul>
<hr>
There is a group of makefiles with support for simultaneous
compilation on multiple platforms and a consistent set of
features that build the <tt>boost_python</tt> library for static
linking, the comprehensive test, and all examples in
<tt>libs/python/example</tt>:
<ul>
<li><a href="../build/vc60.mak">vc60.mak</a>:
Visual C++ 6.0 Service Pack 4
<li><a href="../build/mingw32.mak">mingw32.mak</a>:
mingw32 (Win32-targeted) gcc 2.95.2
<li><a href="../build/linux_gcc.mak">linux_gcc.mak</a>:
gcc 2.95.2 on Linux/Unix
<li><a href="../build/tru64_cxx.mak">tru64_cxx.mak</a>:
Compaq Alpha using the Compaq cxx compiler
<li><a href="../build/irix_CC.mak">irix_CC.mak</a>:
Silicon Graphics IRIX 6.5 CC compiler
</ul>
<a href="http://cctbx.sourceforge.net/page_installation_adv.html#installation_boost_python"
>Usage of these makefiles is described here.</a>
<hr>
There is another group of makefiles for GNU make.
These makefiles are less redundant than the makefiles
in the group above,
but the list of compilation targets is not as complete
and there is no support for simultaneous compilation
on multiple platforms.
<ul>
<li><a href="../build/como.mak">como.mak</a>:
Comeau C++ on Linux
<li><a href="../build/gcc.mak">gcc.mak</a>:
GCC on Linux/Unix.
</ul>
<hr>
A project workspace for Microsoft Visual Studio is provided at <tt><a
href="../build/build.dsw">libs/python/build/build.dsw</a></tt>. The
include paths for this project may need to be changed for your
installation. They currently assume that python has been installed at
<tt>c:\tools\python</tt>. Three configurations of all targets are
supported:
<ul>
<li>Release (optimization, <tt>-DNDEBUG</tt>)
<li>Debug (no optimization <tt>-D_DEBUG</tt>)
<li>DebugPython (no optimization, <tt>-D_DEBUG
-DBOOST_DEBUG_PYTHON</tt>)
</ul>
<p>When extension modules are built with Visual C++ using
<tt>-D_DEBUG</tt>, Python defaults to <i>force</i> linking with a
special debugging version of the Python DLL. Since this debug DLL
isn't supplied with the default Python installation for Windows,
Boost.Python uses <tt><a href=
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a></tt>
to temporarily undefine <tt>_DEBUG</tt> when <tt>Python.h</tt> is
<tt>#include</tt>d.
<p>If you want the extra runtime checks available with the debugging
version of the library, <tt>#define BOOST_DEBUG_PYTHON</tt> to
re-enable library forcing, and link with the DebugPython version of
<tt>boost_python.lib</tt>. You'll need to get the debugging version
of the Python executable (<tt>python_d.exe</tt>) and DLL
(<tt>python20_d.dll</tt> or <tt>python15_d.dll</tt>). The Python
sources include project files for building these. If you <a href=
"http://www.python.org">download</a> them, change the name of the
top-level directory to <tt>src</tt>, and install it under
<tt>c:\tools\python</tt>, the workspace supplied by Boost.Python will
be able to use it without modification. Just open
<tt>c:\tools\python\src\pcbuild\pcbuild.dsw</tt> and invoke "build
all" to generate all the debugging targets.
<p>If you do not <tt>#define BOOST_DEBUG_PYTHON</tt>, be sure that
any source files <tt>#include &lt;<a href=
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a>&gt;</tt>
instead of the usual <tt>Python.h</tt>, or you will have link
incompatibilities.<br>
<hr>
If your platform isn't directly supported, you can build a static
library from the following source files (in the Boost subdirectory
<tt>libs/python/src</tt>), or compile them directly and link the
resulting objects into your extension module:
<ul>
<li><a href=
"../../../libs/python/src/classes.cpp">classes.cpp</a>
<li><a href=
"../../../libs/python/src/conversions.cpp">conversions.cpp</a>
<li><a href=
"../../../libs/python/src/cross_module.cpp">cross_module.cpp</a>
<li><a href=
"../../../libs/python/src/extension_class.cpp">extension_class.cpp</a>
<li><a href=
"../../../libs/python/src/functions.cpp">functions.cpp</a>
<li><a href=
"../../../libs/python/src/init_function.cpp">init_function.cpp</a>
<li><a href=
"../../../libs/python/src/module_builder.cpp">module_builder.cpp</a>
<li><a href=
"../../../libs/python/src/objects.cpp">objects.cpp</a>
<li><a href=
"../../../libs/python/src/types.cpp">types.cpp</a>
</ul>
<hr>
Next: <a href="enums.html">Wrapping Enums</a> Previous: <a href=
"under-the-hood.html">A Peek Under the Hood</a> Up: <a href=
"index.html">Top</a>
<hr>
<p>&copy; 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: Apr 17, 2001 (R.W. Grosse-Kunstleve)
</div>

View File

@@ -6,20 +6,23 @@
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Comparisons with
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)"><br>
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 &ldquo;dealing with Python objects&rdquo;, 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.
Like Boost.Python, <a href="http://cxx.sourceforge.net/">CXX</a> attempts to
provide a C++-oriented interface to Python. In most cases, as with the
boost library, it relieves the user from worrying about
reference-counts. Both libraries automatically convert thrown C++
exceptions into Python exceptions. As far as I can tell, CXX has 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.
<p>
CXX claims to interoperate well with the C++ Standard Library
@@ -38,11 +41,15 @@
<p>
As far as I can tell, 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. I think it would be fair
to say that while you're not programming directly to the &ldquo;bare
metal&rdquo; with CXX, in comparison to py_cpp, it presents a low-level
interface to Python. That use is also supported by the py_cpp object
wrappers.
same fully-generic interfaces we use in Python. While you're hardly
programming directly to the ``bare metal'' with CXX, it basically
presents a ``C++-ized'' version of the Python 'C' API. Some fraction of
that capability is available in Boost.Python through <tt><a
href="../../../boost/python/objects.hpp">boost/python/objects.hpp</a></tt>,
which provides C++ objects corresponding to Python lists, tuples,
strings, and dictionaries, and through <tt><a
href="../../../boost/python/callback.hpp">boost/python/callback.hpp</a></tt>,
which allows you to call back into python with C++ arguments.
<p>
<a href="mailto:dubois1@llnl.gov">Paul F. Dubois</a>, the original
@@ -51,11 +58,11 @@
fill in the other half. Here is his response to the commentary above:
<blockquote>
&ldquo;My intention with CXX was not to do what you are doing. It was to enable a
``My intention with CXX was not to do what you are doing. It was to enable a
person to write an extension directly in C++ rather than C. I figured others had
the wrapping business covered. I thought maybe CXX would provide an easier
target language for those making wrappers, but I never explored
that.&rdquo;<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
that.''<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
</blockquote>
<h2>SWIG</h2>
@@ -65,28 +72,28 @@ that.&rdquo;<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
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
many Python extension modules. Like Boost.Python, SWIG is trying to allow an
existing interface to be wrapped with little or no change to the
existing code. The documentation says &ldquo;SWIG parses a form of ANSI C
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.&rdquo; For C++ interfaces, the tweaking has often
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> &ldquo;The problem with swig (when I used it) is that it
<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 doesn't have
realistic), one had to write code by hand. I believe Boost.Python doesn't have
this problem[<a href="#sic">sic</a>]... IMHO overloaded functions are very important to
wrap correctly.&rdquo;<br><i>-Prabhu Ramachandran</i>
wrap correctly.''<br><i>-Prabhu Ramachandran</i>
</blockquote>
<p>
By contrast, py_cpp doesn't attempt to parse C++ - the problem is simply
By contrast, Boost.Python doesn't attempt to parse C++ - the problem is simply
too complex to do correctly. <a name="sic">Technically</a>, one does
write code by hand to use py_cpp. The goal, however, has been to make
write code by hand to use Boost.Python. 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.
@@ -95,7 +102,7 @@ that.&rdquo;<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
<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
C++-oriented. The author says that like Boost.Python, 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
@@ -113,7 +120,7 @@ that.&rdquo;<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
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
provide an implementation. Unlike Boost.Python, 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
@@ -124,7 +131,7 @@ that.&rdquo;<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
<a
href="http://www.python.org/workshops/1996-11/papers/GRAD/html/GRADcover.html">GRAD</a>
is another very ambitious project aimed at generating Python wrappers for
interfaces written in &ldquo;legacy languages&rdquo;, among which C++ is the first one
interfaces written in ``legacy languages'', among which C++ is the first one
implemented. Like SWIG, it aims to parse source code and automatically
generate wrappers, though it appears to take a more sophisticated approach
to parsing in general and C++ in particular, so it should do a much better
@@ -148,73 +155,77 @@ an inheritance relationship?
<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
ExtensionClasses in Zope</a> use the same underlying mechanism as Boost.Python
to support subclassing of extension types in Python, including
multiple-inheritance. Both systems support pickling/unpickling of
extension class instances in very similar ways. Both systems rely on the
same &ldquo;<a
same ``<a
href="http://www.python.org/workshops/1994-11/BuiltInClasses/Welcome.html">Don
Beaudry Hack</a>&rdquo; that also inspired Don's MESS System.
Beaudry Hack</a>'' that also inspired Don's MESS System.
<p>
The major differences are:
<ul>
<li>Zope is entirely 'C' language-based. It doesn't require a C++
compiler, so it's much more portable than Boost.Python, which stresses
the limits of even some modern C++ implementations.
<li>
py_cpp lifts the burden on the user to parse and convert function
Boost.Python 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
Boost.Python lifts the burden on the user to maintain Python
reference-counts.
<li>
py_cpp supports function overloading; Zope does not.
Boost.Python supports function overloading; Zope does not.
<li>
py_cpp supplies a simple mechanism for exposing read-only and
Boost.Python 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
exposing a C++ class to python using Boost.Python (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 &ldquo;the need for a
C-based persistence mechanism&rdquo;. Py_cpp's are motivated by the desire
Zope's ExtensionClasses are specifically motivated by ``the need for a
C-based persistence mechanism''. Boost.Python's are motivated by the desire
to simply reflect a C++ API into Python with as little modification as
possible.
<li>
The following Zope restriction does not apply to py_cpp: &ldquo;At most one
The following Zope restriction does not apply to Boost.Python: ``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.&rdquo;
provide extension methods but no data.''
<li>
Zope requires use of the somewhat funky inheritedAttribute (search for
&ldquo;inheritedAttribute&rdquo; on <a
``inheritedAttribute'' on <a
href="http://www.digicool.com/releases/ExtensionClass">this page</a>)
method to access base class methods. In py_cpp, base class methods can
method to access base class methods. In Boost.Python, base class methods can
be accessed in the usual way by writing
&ldquo;<code>BaseClass.method</code>&rdquo;.
``<code>BaseClass.method</code>''.
<li>
Zope supplies some creative but esoteric idioms such as <a href=
"http://www.digicool.com/releases/ExtensionClass/Acquisition.html">
Acquisition</a>. No specific support for this is built into py_cpp.
Acquisition</a>. No specific support for this is built into Boost.Python.
<li>
Zope's ComputedAttribute support is designed to be used from Python.
<a href="special.html#getter_setter">The analogous feature of
py_cpp</a> can be used from C++ or Python. The feature is arguably
easier to use in py_cpp.
Boost.Python</a> can be used from C++ or Python. The feature is arguably
easier to use in Boost.Python.
</ul>
<p>
Next: <a href="example1.html">A Simple Example Using Boost.Python</a>
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="index.html">Top</a>
<p>
&copy; 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 &ldquo;as is&rdquo; without
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: Nov 26, 2000
Updated: Mar 6, 2001
</div>

336
doc/cross_module.html Normal file
View File

@@ -0,0 +1,336 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>Cross-extension-module dependencies</title>
<div>
<img src="../../../c++boost.gif"
alt="c++boost.gif (8819 bytes)"
align="center"
width="277" height="86">
<hr>
<h1>Cross-extension-module dependencies</h1>
It is good programming practice to organize large projects as modules
that interact with each other via well defined interfaces. With
Boost.Python it is possible to reflect this organization at the C++
level at the Python level. This is, each logical C++ module can be
organized as a separate Python extension module.
<p>
At first sight this might seem natural and straightforward. However, it
is a fairly complex problem to establish cross-extension-module
dependencies while maintaining the same ease of use Boost.Python
provides for classes that are wrapped in the same extension module. To
a large extent this complexity can be hidden from the author of a
Boost.Python extension module, but not entirely.
<hr>
<h2>The recipe</h2>
Suppose there is an extension module that exposes certain instances of
the C++ <tt>std::vector</tt> template library such that it can be used
from Python in the following manner:
<pre>
import std_vector
v = std_vector.double([1, 2, 3, 4])
v.push_back(5)
v.size()
</pre>
Suppose the <tt>std_vector</tt> module is done well and reflects all
C++ functions that are useful at the Python level, for all C++ built-in
data types (<tt>std_vector.int</tt>, <tt>std_vector.long</tt>, etc.).
<p>
Suppose further that there is statistic module with a C++ class that
has constructors or member functions that use or return a
<tt>std::vector</tt>. For example:
<pre>
class xy {
public:
xy(const std::vector&lt;double&gt;&amp; x, const std::vector&lt;double&gt;&amp; y) : m_x(x), m_y(y) {}
const std::vector&lt;double&gt;&amp; x() const { return m_x; }
const std::vector&lt;double&gt;&amp; y() const { return m_y; }
double correlation();
private:
std::vector&lt;double&gt; m_x;
std::vector&lt;double&gt; m_y;
}
</pre>
What is more natural than reusing the <tt>std_vector</tt> extension
module to expose these constructors or functions to Python?
<p>
Unfortunately, what seems natural needs a little work in both the
<tt>std_vector</tt> and the <tt>statistics</tt> module.
<p>
In the <tt>std_vector</tt> extension module,
<tt>std::vector&lt;double&gt;</tt> is exposed to Python in the usual
way with the <tt>class_builder&lt;&gt;</tt> template. To also enable the
automatic conversion of <tt>std::vector&lt;double&gt;</tt> function
arguments or return values in other Boost.Python C++ modules, the
converters that convert a <tt>std::vector&lt;double&gt;</tt> C++ object
to a Python object and vice versa (i.e. the <tt>to_python()</tt> and
<tt>from_python()</tt> template functions) have to be exported. For
example:
<pre>
#include &lt;boost/python/cross_module.hpp&gt;
//...
class_builder&lt;std::vector&lt;double&gt; &gt; v_double(std_vector_module, &quot;double&quot;);
export_converters(v_double);
</pre>
In the extension module that wraps <tt>class xy</tt> we can now import
these converters with the <tt>import_converters&lt;&gt;</tt> template.
For example:
<pre>
#include &lt;boost/python/cross_module.hpp&gt;
//...
import_converters&lt;std::vector&lt;double&gt; &gt; v_double_converters(&quot;std_vector&quot;, &quot;double&quot;);
</pre>
That is all. All the attributes that are defined for
<tt>std_vector.double</tt> in the <tt>std_vector</tt> Boost.Python
module will be available for the returned objects of <tt>xy.x()</tt>
and <tt>xy.y()</tt>. Similarly, the constructor for <tt>xy</tt> will
accept objects that were created by the <tt>std_vector</tt>module.
<hr>
<h2>Placement of <tt>import_converters&lt;&gt;</tt> template instantiations</h2>
<tt>import_converts&lt;&gt;</tt> can be viewed as a drop-in replacement
for <tt>class_wrapper&lt;&gt;</tt>, and the recommendations for the
placement of <tt>class_wrapper&lt;&gt;</tt> template instantiations
also apply to to <tt>import_converts&lt;&gt;</tt>. In particular, it is
important that an instantiation of <tt>class_wrapper&lt;&gt;</tt> is
visible to any code which wraps a C++ function with a <tt>T</tt>,
<tt>T*</tt>, const <tt>T&amp;</tt>, etc. parameter or return value.
Therefore you may want to group all <tt>class_wrapper&lt;&gt;</tt> and
<tt>import_converts&lt;&gt;</tt> instantiations at the top of your
module's init function, then <tt>def()</tt> the member functions later
to avoid problems with inter-class dependencies.
<hr>
<h2>Non-copyable types</h2>
<tt>export_converters()</tt> instantiates C++ template functions that
invoke the copy constructor of the wrapped type. For a type that is
non-copyable this will result in compile-time error messages. In such a
case, <tt>export_converters_noncopyable()</tt> can be used to export
the converters that do not involve the copy constructor of the wrapped
type. For example:
<pre>
class_builder&lt;store&gt; py_store(your_module, &quot;store&quot;);
export_converters_noncopyable(py_store);
</pre>
The corresponding <tt>import_converters&lt;&gt;</tt> statement does not
need any special attention:
<pre>
import_converters&lt;store&gt; py_store(&quot;noncopyable_export&quot;, &quot;store&quot;);
</pre>
<hr>
<h2>Python module search path</h2>
The <tt>std_vector</tt> and <tt>statistics</tt> modules can now be used
in the following way:
<pre>
import std_vector
import statistics
x = std_vector.double([1, 2, 3, 4])
y = std_vector.double([2, 4, 6, 8])
xy = statistics.xy(x, y)
xy.correlation()
</pre>
In this example it is clear that Python has to be able to find both the
<tt>std_vector</tt> and the <tt>statistics</tt> extension module. In
other words, both extension modules need to be in the Python module
search path (<tt>sys.path</tt>).
<p>
The situation is not always this obvious. Suppose the
<tt>statistics</tt> module has a <tt>random()</tt> function that
returns a vector of random numbers with a given length:
<pre>
import statistics
x = statistics.random(5)
y = statistics.random(5)
xy = statistics.xy(x, y)
xy.correlation()
</pre>
A naive user will not easily anticipate that the <tt>std_vector</tt>
module is used to pass the <tt>x</tt> and <tt>y</tt> vectors around. If
the <tt>std_vector</tt> module is in the Python module search path,
this form of ignorance is of no harm. On the contrary, we are glad
that we do not have to bother the user with details like this.
<p>
If the <tt>std_vector</tt> module is not in the Python module search
path, a Python exception will be raised:
<pre>
Traceback (innermost last):
File &quot;foo.py&quot;, line 2, in ?
x = statistics.random(5)
ImportError: No module named std_vector
</pre>
As is the case with any system of a non-trivial complexity, it is
important that the setup is consistent and complete.
<hr>
<h2>Two-way module dependencies</h2>
Boost.Python supports two-way module dependencies. This is best
illustrated by a simple example.
<p>
Suppose there is a module <tt>ivect</tt> that implements vectors of
integers, and a similar module <tt>dvect</tt> that implements vectors
of doubles. We want to be able do convert an integer vector to a double
vector and vice versa. For example:
<pre>
import ivect
iv = ivect.ivect((1,2,3,4,5))
dv = iv.as_dvect()
</pre>
The last expression will implicitly import the <tt>dvect</tt> module in
order to enable the conversion of the C++ representation of
<tt>dvect</tt> to a Python object. The analogous is possible for a
<tt>dvect</tt>:
<pre>
import dvect
dv = dvect.dvect((1,2,3,4,5))
iv = dv.as_ivect()
</pre>
Now the <tt>ivect</tt> module is imported implicitly.
<p>
Note that the two-way dependencies are possible because the
dependencies are resolved only when needed. This is, the initialization
of the <tt>ivect</tt> module does not rely on the <tt>dvect</tt>
module, and vice versa. Only if <tt>as_dvect()</tt> or
<tt>as_ivect()</tt> is actually invoked will the corresponding module
be implicitly imported. This also means that, for example, the
<tt>dvect</tt> module does not have to be available at all if
<tt>as_dvect()</tt> is never used.
<hr>
<h2>Clarification of compile-time and link-time dependencies</h2>
Boost.Python's support for resolving cross-module dependencies at
runtime does not imply that compile-time dependencies are eliminated.
For example, the statistics extension module in the example above will
need to <tt>#include &lt;vector&gt;</tt>. This is immediately obvious
from the definition of <tt>class xy</tt>.
<p>
If a library is wrapped that consists of both header files and compiled
components (e.g. <tt>libdvect.a</tt>, <tt>dvect.lib</tt>, etc.), both
the Boost.Python extension module with the
<tt>export_converters()</tt> statement and the module with the
<tt>import_converters&lt;&gt;</tt> statement need to be linked against
the object library. Ideally one would build a shared library (e.g.
<tt>libdvect.so</tt>, <tt>dvect.dll</tt>, etc.). However, this
introduces the issue of having to configure the search path for the
dynamic loading correctly. For small libraries it is therefore often
more convenient to ignore the fact that the object files are loaded
into memory more than once.
<hr>
<h2>Summary of motivation for cross-module support</h2>
The main purpose of Boost.Python's cross-module support is to allow for
a modular system layout. With this support it is straightforward to
reflect C++ code organization at the Python level. Without the
cross-module support, a multi-purpose module like <tt>std_vector</tt>
would be impractical because the entire wrapper code would somehow have
to be duplicated in all extension modules that use it, making them
harder to maintain and harder to build.
<p>
Another motivation for the cross-module support is that two extension
modules that wrap the same class cannot both be imported into Python.
For example, if there are two modules <tt>A</tt> and <tt>B</tt> that
both wrap a given <tt>class X</tt>, this will work:
<pre>
import A
x = A.X()
</pre>
This will also work:
<pre>
import B
x = B.X()
</pre>
However, this will fail:
<pre>
import A
import B
python: /net/cci/rwgk/boost/boost/python/detail/extension_class.hpp:866:
static void boost::python::detail::class_registry&lt;X&gt;::register_class(boost::python::detail::extension_class_base *):
Assertion `static_class_object == 0' failed.
Abort
</pre>
A good solution is to wrap <tt>class X</tt> only once. Depending on the
situation, this could be done by module <tt>A</tt> or <tt>B</tt>, or an
additional small extension module that only wraps and exports
<tt>class X</tt>.
<p>
Finally, there can be important psychological or political reasons for
using the cross-module support. If a group of classes is lumped
together with many others in a huge module, the authors will have
difficulties in being identified with their work. The situation is
much more transparent if the work is represented by a module with a
recognizable name. This is not just a question of strong egos, but also
of getting credit and funding.
<hr>
<h2>Why not use <tt>export_converters()</tt> universally?</h2>
There is some overhead associated with the Boost.Python cross-module
support. Depending on the platform, the size of the code generated by
<tt>export_converters()</tt> is roughly 10%-20% of that generated
by <tt>class_builder&lt;&gt;</tt>. For a large extension module with
many wrapped classes, this could mean a significant difference.
Therefore the general recommendation is to use
<tt>export_converters()</tt> only for classes that are likely to
be used as function arguments or return values in other modules.
<hr>
&copy; Copyright Ralf W. Grosse-Kunstleve 2001. 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: April 2001
</div>

192
doc/data_structures.txt Normal file
View File

@@ -0,0 +1,192 @@
Given a real Python class 'A', a wrapped C++ class 'B', and this definition:
class C(A, B):
def __init__(self):
B.__init__(self)
self.x = 1
...
c = C()
this diagram describes the internal structure of an instance of 'C', including
its inheritance relationships. Note that ExtensionClass<B> is derived from
Class<ExtensionInstance>, and is in fact identical for all intents and purposes.
MetaClass<ExtensionInstance>
+---------+ +---------+
types.ClassType: | | | |
| | | |
| | | |
+---------+ +---------+
^ ^ ^
PyClassObject | ExtensionClass<B> | |
A: +------------+ | B: +------------+ | |
| ob_type -+-+ | ob_type -+-----+ |
| | ()<--+- __bases__ | |
| | | __dict__ -+->{...} |
| | 'B'<-+- __name__ | |
+------------+ +------------+ |
^ ^ |
| | |
+-----+ +-------------+ |
| | |
| | Class<ExtensionInstance> |
| | C: +------------+ |
| | | ob_type -+------------+
tuple:(*, *)<--+- __bases__ |
| __dict__ -+->{__module__, <methods, etc.>}
'C' <-+- __name__ |
+------------+
^ (in case of inheritance from more than one
| extension class, this vector would contain
+---------------+ a pointer to an instance holder for the data
| of each corresponding C++ class)
| ExtensionInstance
| c: +---------------------+ std::vector<InstanceHolderBase>
+----+- __class__ | +---+--
| m_wrapped_objects -+->| * | ...
{'x': 1}<-+- __dict__ | +-|-+--
+---------------------+ | InstanceValueHolder<B>
| +--------------------------------+
+-->| (contains a C++ instance of B) |
+--------------------------------+
In our inheritance test cases in extclass_demo.cpp/test_extclass.py, we have the
following C++ inheritance hierarchy:
+-----+ +----+
| A1 | | A2 |
+-----+ +----+
^ ^ ^ ^ ^
| | | | |
+-----+ | +---------+-----+
| | | |
| +---+----------+
.......!...... | |
: A_callback : +-+--+ +-+--+
:............: | B1 | | B2 |
+----+ +----+
^
|
+-------+---------+
| |
+-+-+ ......!.......
| C | : B_callback :
+---+ :............:
A_callback and B_callback are used as part of the wrapping mechanism but not
represented in Python. C is also not represented in Python but is delivered
there polymorphically through a smart pointer.
This is the data structure in Python.
ExtensionClass<A1>
A1: +------------+
()<--+- __bases__ |
| __dict__ -+->{...}
+------------+
^
| ExtensionInstance
| a1: +---------------------+ vec InstanceValueHolder<A1,A_callback>
+---------+- __class__ | +---+ +---------------------+
| | m_wrapped_objects -+->| *-+-->| contains A_callback |
| +---------------------+ +---+ +---------------------+
|
| ExtensionInstance
| pa1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ A1
| +---------------------+ +---+ +---+ | +---+
| +->| |
| ExtensionInstance +---+
| pb1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1
| +---------------------+ +---+ +---+ | +---+
| +->| |
| ExtensionInstance +---+
| pb2_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ B2
| +---------------------+ +---+ +---+ | +---+
| +->| |
| +---+
| ExtensionClass<A1>
| A2: +------------+
| ()<--+- __bases__ |
| | __dict__ -+->{...}
| +------------+
| ^
| | ExtensionInstance
| a2: | +---------------------+ vec InstanceValueHolder<A2>
| +-+- __class__ | +---+ +-------------+
| | | m_wrapped_objects -+->| *-+-->| contains A2 |
| | +---------------------+ +---+ +-------------+
| |
| | ExtensionInstance
| pa2_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
| +-+- __class__ | +---+ +---+
| | | m_wrapped_objects -+->| *-+-->| *-+-+ A2
| | +---------------------+ +---+ +---+ | +---+
| | +->| |
| | ExtensionInstance +---+
| pb1_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
| +-+- __class__ | +---+ +---+
| | | m_wrapped_objects -+->| *-+-->| *-+-+ B1
| | +---------------------+ +---+ +---+ | +---+
| | +->| |
| | +---+
| |
| +---------------+------------------------------+
| | |
+------+-------------------------+-|----------------------------+ |
| | | | |
| Class<ExtensionInstance> | | ExtensionClass<B1> | | ExtensionClass<B1>
| DA1: +------------+ | | B1: +------------+ | | B2: +------------+
(*,)<---+- __bases__ | (*,*)<---+- __bases__ | (*,*)<---+- __bases__ |
| __dict__ -+->{...} | __dict__ -+->{...} | __dict__ -+->{...}
+------------+ +------------+ +------------+
^ ^ ^
| ExtensionInstance | |
| da1: +---------------------+ | vec InstanceValueHolder<A1,A_callback>
+-------+- __class__ | | +---+ +---------------------+ |
| m_wrapped_objects -+--|-->| *-+-->| contains A_callback | |
+---------------------+ | +---+ +---------------------+ |
+--------------------------------------+ |
| ExtensionInstance |
b1: | +---------------------+ vec InstanceValueHolder<B1,B_callback> |
+-+- __class__ | +---+ +---------------------+ |
| | m_wrapped_objects -+->| *-+-->| contains B_callback | |
| +---------------------+ +---+ +---------------------+ |
| |
| ExtensionInstance |
pb1_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
+-+- __class__ | +---+ +---+ |
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1 |
| +---------------------+ +---+ +---+ | +---+ |
| +->| | |
| ExtensionInstance +---+ |
pc_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
+-+- __class__ | +---+ +---+ |
| | m_wrapped_objects -+->| *-+-->| *-+-+ C |
| +---------------------+ +---+ +---+ | +---+ |
| +->| | |
| +---+ |
| |
| Class<ExtensionInstance> +---------------------------------------+
| DB1: +------------+ | ExtensionInstance
(*,)<---+- __bases__ | a2: | +---------------------+ vec InstanceValueHolder<A2>
| __dict__ -+->{...} +-+- __class__ | +---+ +-------------+
+------------+ | m_wrapped_objects -+->| *-+-->| contains A2 |
^ +---------------------+ +---+ +-------------+
| ExtensionInstance
db1: | +---------------------+ vec InstanceValueHolder<B1,B_callback>
+-+- __class__ | +---+ +----------------------+
| m_wrapped_objects -+-->| *-+-->| contains B1_callback |
+---------------------+ +---+ +----------------------+

View File

@@ -6,33 +6,54 @@
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Wrapping enums
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)"><br>
Wrapping enums
</h1>
<p>Because there is in general no way to deduce that a value of arbitrary type T
is an enumeration constant, py_cpp cannot automatically convert enum values to
and from Python. To handle this case, you need to decide how you want the enum
to show up in Python (since Python doesn't have enums). Once you have done that,
you can write some simple <code>from_python()</code> and
<code>to_python()</code> functions.
is an enumeration constant, the Boost Python Library cannot automatically
convert enum values to and from Python. To handle this case, you need to decide
how you want the enum to show up in Python (since Python doesn't have
enums). Once you have done that, you can write some simple
<code>from_python()</code> and <code>to_python()</code> functions.
<p>If you are satisfied with a Python int as a way to represent your enum
values, py_cpp provides a shorthand for these functions. You just need to
instantiate <code>boost::python::enum_as_int_converters&lt;EnumType&gt;</code> where
values, we provide a shorthand for these functions. You just need to cause
<code>boost::python::enum_as_int_converters&lt;EnumType&gt;</code> to be
instantiated, where
<code>EnumType</code> is your enumerated type. There are two convenient ways to do this:
<ol>
<li><blockquote>
<li>Explicit instantiation:
<blockquote><pre>
template class boost::python::enum_as_int_converters&lt;my_enum&gt;;
</blockquote></pre>
Some buggy C++ implementations require a class to be instantiated in the same
namespace in which it is defined. In that case, the simple incantation above becomes:
<blockquote>
<pre>
...
} // close my_namespace
// drop into namespace python and explicitly instantiate
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
template class enum_as_int_converters<extclass_demo::EnumOwner::enum_type>;
BOOST_PYTHON_END_CONVERSION_NAMESPACE
namespace boost { namespace python {
template class enum_as_int_converters&lt;my_enum_type&gt;;
}} // namespace boost::python
namespace my_namespace { // re-open my_namespace
...
</pre>
</blockquote>
<li><blockquote><pre>
<li>If you have such an implementation, you may find this technique more convenient
<blockquote><pre>
// instantiate as base class in any namespace
struct EnumTypeConverters
: boost::python::py_enum_as_int_converters<EnumType>
: boost::python::enum_as_int_converters&lt;EnumType&gt;
{
};
</blockquote></pre>
@@ -66,7 +87,8 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE
<code>long</code> type.
You may also want to add a bunch of lines like this to your module
initialization:
initialization. These bind the corresponding enum values to the appropriate
names so they can be used from Python:
<blockquote><pre>
mymodule.add(boost::python::to_python(enum_value_1), "enum_value_1");
@@ -78,17 +100,21 @@ You can also add these to an extension class definition, if your enum happens to
be local to a class and you want the analogous interface in Python:
<blockquote><pre>
my_class.add(boost::python::to_python(enum_value_1), "enum_value_1");
my_class.add(boost::python::to_python(enum_value_2), "enum_value_2");
my_class_builder.add(boost::python::to_python(enum_value_1), "enum_value_1");
my_class_builder.add(boost::python::to_python(enum_value_2), "enum_value_2");
...
</pre></blockquote>
<p>
Next: <a href="pointers.html">Pointers and Smart Pointers</a>
Previous: <a href="building.html">Building an Extension Module</a>
Up: <a href="index.html">Top</a>
<p>
&copy; 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 &ldquo;as
is&rdquo; without express or implied warranty, and with no claim as to
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: Nov 26, 2000
Updated: Mar 6, 2001
</div>

View File

@@ -1,7 +1,7 @@
<!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
A Simple Example
</title>
<div>
<h1>
@@ -9,7 +9,7 @@
"c++boost.gif (8819 bytes)">
</h1>
<h1>
A Simple Example Using py_cpp
A Simple Example
</h1>
<p>
Suppose we have the following C++ API which we want to expose in
@@ -18,104 +18,57 @@
<pre>
#include &lt;string&gt;
namespace hello {
  class world
  {
   public:
      world(int);
      ~world();
      std::string get() const { return "hi, world"; }
    ...
  };
  std::size_t length(const world&amp; x) { return std::strlen(x.get()); }
namespace { // Avoid cluttering the global namespace.
// A couple of simple C++ functions that we want to expose to Python.
std::string greet() { return "hello, world"; }
int square(int number) { return number * number; }
}
</pre>
</blockquote>
<p>
Here is the C++ code for a python module called <code>hello</code>
which exposes the API using py_cpp:
Here is the C++ code for a python module called <tt>getting_started1</tt>
which exposes the API.
<blockquote>
<pre>
#include <boost/python/class_builder.hpp>
// Python requires an exported function called init&lt;module-name&gt; in every
// extension module. This is where we build the module contents.
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
void inithello()
#include &lt;boost/python/class_builder.hpp&gt;
namespace python = boost::python;
BOOST_PYTHON_MODULE_INIT(getting_started1)
{
    try
    {
       // create an object representing this extension module
       boost::python::module_builder hello("hello");
       // Create the Python type object for our extension class
       boost::python::class_builder&lt;hello::world&gt; world_class(hello, "world");
       // Add the __init__ function
       world_class.def(boost::python::constructor&lt;int&gt;());
       // Add a regular member function
       world_class.def(&amp;hello::world::get, "get");
       // Add a regular function to the module
       hello.def(hello::length, "length");
    }
    catch(...)
    {
       boost::python::handle_exception();    // Deal with the exception for Python
    }
try
{
// Create an object representing this extension module.
python::module_builder this_module("getting_started1");
// Add regular functions to the module.
this_module.def(greet, "greet");
this_module.def(square, "square");
}
catch(...)
{
python::handle_exception(); // Deal with the exception for Python
}
}
// Win32 DLL boilerplate
#if defined(_WIN32)
#include &lt;windows.h&gt;
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
PYTHONPATH</code> we can now access our C++ functions from
Python.
<blockquote>
<pre>
&gt;&gt;&gt; import hello
&gt;&gt;&gt; hi_world = hello.world(3)
&gt;&gt;&gt; hi_world.get()
'hi, world'
&gt;&gt;&gt; hello.length(hi_world)
9
&gt;&gt;&gt; import getting_started1
&gt;&gt;&gt; print getting_started1.greet()
hello, world
&gt;&gt;&gt; number = 11
&gt;&gt;&gt; print number, '*', number, '=', getting_started1.square(number)
11 * 11 = 121
</pre>
</blockquote>
<p>
We can even make a subclass of <code>hello.world</code>:
<blockquote>
<pre>
&gt;&gt;&gt; class my_subclass(hello.world):
...     def get(self):
...         return 'hello, world'
...
&gt;&gt;&gt; y = my_subclass(4)
&gt;&gt;&gt; y.get()
'hello, world'
</pre>
</blockquote>
<p>
Pretty cool! You can't do that with an ordinary Python extension type!
<blockquote>
<pre>
&gt;&gt;&gt; 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:
Next: <a href="exporting_classes.html">Exporting Classes</a>
Previous: <a href="comparisons.html">Comparisons with other systems</a> Up:
<a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
@@ -124,6 +77,6 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Nov 26, 2000
Updated: Mar 6, 2000
</div>

144
doc/exporting_classes.html Normal file
View File

@@ -0,0 +1,144 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Exporting Classes
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" src="../../../c++boost.gif" alt=
"c++boost.gif (8819 bytes)">
</h1>
<h1>
Exporting Classes
</h1>
<p>
Now let's expose a C++ class to Python:
<blockquote><pre>
#include &lt;iostream&gt;
#include &lt;string&gt;
namespace { // Avoid cluttering the global namespace.
// A friendly class.
class hello
{
public:
hello(const std::string&amp; country) { this-&gt;country = country; }
std::string greet() const { return "Hello from " + country; }
private:
std::string country;
};
// A function taking a hello object as an argument.
std::string invite(const hello&amp; w) {
return w.greet() + "! Please come soon!";
}
}
</blockquote></pre> <p>
To expose the class, we use a <tt>class_builder</tt> in addition to the
<tt>module_builder</tt> from the previous example. Class member functions
are exposed by using the <tt>def()</tt> member function on the
<tt>class_builder</tt>:
<blockquote><pre>
#include &lt;boost/python/class_builder.hpp&gt;
namespace python = boost::python;
BOOST_PYTHON_MODULE_INIT(getting_started2)
{
try
{
// Create an object representing this extension module.
python::module_builder this_module("getting_started2");
// Create the Python type object for our extension class.
python::class_builder&lt;hello&gt; hello_class(this_module, "hello");
// Add the __init__ function.
hello_class.def(python::constructor&lt;std::string&gt;());
// Add a regular member function.
hello_class.def(&amp;hello::greet, "greet");
// Add invite() as a regular function to the module.
this_module.def(invite, "invite");
// Even better, invite() can also be made a member of hello_class!!!
hello_class.def(invite, "invite");
}
catch(...)
{
python::handle_exception(); // Deal with the exception for Python
}
}
</blockquote></pre>
<p>
Now we can use the class normally from Python:
<blockquote><pre>
&gt;&gt;&gt; from getting_started2 import *
&gt;&gt;&gt; hi = hello('California')
&gt;&gt;&gt; hi.greet()
'Hello from California'
&gt;&gt;&gt; invite(hi)
'Hello from California! Please come soon!'
&gt;&gt;&gt; hi.invite()
'Hello from California! Please come soon!'
</blockquote></pre>
Notes:<ul>
<li> We expose the class' constructor by calling <tt>def()</tt> on the
<tt>class_builder</tt> with an argument whose type is
<tt>constructor&lt;</tt><i>params</i><tt>&gt;</tt>, where <i>params</i>
matches the list of constructor argument types:
<li>Regular member functions are defined by calling <tt>def()</tt> with a
member function pointer and its Python name:
<li>Any function added to a class whose initial argument matches the class (or
any base) will act like a member function in Python.
</ul>
<p>
We can even make a subclass of <code>hello.world</code>:
<blockquote><pre>
&gt;&gt;&gt; class wordy(hello):
... def greet(self):
... return hello.greet(self) + ', where the weather is fine'
...
&gt;&gt;&gt; hi2 = wordy('Florida')
&gt;&gt;&gt; hi2.greet()
'Hello from Florida, where the weather is fine'
&gt;&gt;&gt; invite(hi2)
'Hello from Florida! Please come soon!'
</blockquote></pre>
<p>
Pretty cool! You can't do that with an ordinary Python extension type!
Of course, you may now have a slightly empty feeling in the pit of
your little pythonic stomach. Perhaps you wanted to see the following
<tt>wordy</tt> invitation:
<blockquote><pre>
'Hello from Florida, where the weather is fine! Please come soon!'
</blockquote></pre>
After all, <tt>invite</tt> calls <tt>hello::greet()</tt>, and you
reimplemented that in your Python subclass, <tt>wordy</tt>. If so, <a
href= "overriding.html">read on</a>...
<p>
Next: <a href="overriding.html">Overridable virtual functions</a>
Previous: <a href="example1.html">A Simple Example</a> Up:
<a href="index.html">Top</a>
<p>
&copy; 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: Mar 6, 2001
</div>

View File

@@ -38,11 +38,11 @@
</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>
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. The Boost Python Library is designed to
lift most of that burden.<br>
<br>
<p>
@@ -56,10 +56,10 @@
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
extension module. Boost.Python 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
like regular Python classes. Boost.Python 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

View File

@@ -1,29 +1,24 @@
<!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
The Boost Python Library (Boost.Python)
</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>
align="center" height="86"><br>The Boost Python Library (Boost.Python)
</h1>
<p>
The source code for py_cpp, including a MSVC demo project is available <a
href="py_cpp_20001106.zip">here</a>.
<h2>Synopsis</h2>
<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
Use the Boost Python Library to quickly and easily export a C++ library to <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 &ldquo;reflect&rdquo; your C++ classes and functions into
Python. The major features of py_cpp include support for:
your C++ classes in any way in order to use them with Boost.Python. The system
<em>should</em> simply ``reflect'' your C++ classes and functions into
Python. The major features of Boost.Python include support for:
<ul>
<li><a href="inheritance.hml">Subclassing extension types in Python</a>
<li><a href="inheritance.html">Subclassing extension types in Python</a>
<li><a href="overriding.html">Overriding virtual functions in Python</a>
<li><a href="overloading.html">[Member] function Overloading</a>
<li><a href="special.html#numeric_auto">Automatic wrapping of numeric operators</a>
@@ -32,9 +27,27 @@ among others.
<h2>Supported Platforms</h2>
<p>py_cpp has been tested in the following configurations:
<p>Boost.Python is known to have been tested in the following configurations:
<ul>
<li>Against Python 2.0 using the following compiler/library combinations:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
with the native library.
<li>An upcoming release of <a
href="http://www.metrowerks.com/products/windows/">Metrowerks
CodeWarrior Pro6 for Windows</a> with the native library (the first
release has a bug that's fatal to Boost.Python)
<li><a
href="http://developer.intel.com/software/products/compilers/c50/">Intel
C++ 5.0</a>. Compilation succeeds, but tests <font
color="#FF0000"><b>FAILED at runtime</b></font> due to a bug in its
exception-handling implementation.
</ul>
<li>Against Python 1.5.2 using the following compiler/library:
<ul>
@@ -56,29 +69,17 @@ among others.
href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve</a>]
<li>An upcoming release of <a href="http://www.metrowerks.com/products/windows/">Metrowerks CodeWarrior
Pro6 for Windows</a> (the first release has a bug that's fatal to py_cpp)
Pro6 for Windows</a> (the first release has a bug that's fatal to Boost.Python)
</ul>
<br>
<li>Against Python 2.0 using the following compiler/library combinations:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a> [by
<a href="mailto:aleaxit@yahoo.com">Alex Martelli</a>]
</ul>
</ul>
<p>Py_cpp requires the <a href="http://www.boost.org">boost</a> libraries, and is
has been accepted for inclusion into the boost libraries pending &ldquo;boostification&ldquo;
(completion of the documentation, change in some naming conventions and
resolution of some namespace issues).
<h2>Credits</h2>
<ul>
<li><a href="mailto:abrahams@mediaone.net">David Abrahams</a> originated
and wrote py_cpp.
<li><a href="../../../people/dave_abrahams.htm">David Abrahams</a> originated
and wrote most of the library, and continues to coordinate development.
<li><a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich Koethe</a>
had independently developed a similar system. When he discovered py_cpp,
had independently developed a similar system. When he discovered Boost.Python,
he generously contributed countless hours of coding and much insight into
improving it. He is responsible for an early version of the support for <a
href="overloading.html">function overloading</a> and wrote the support for
@@ -87,16 +88,22 @@ among others.
Python and C++, and has designed an extremely easy-to-use way of
exposing <a href="special.html#numeric">numeric operators</a>, including
a way to avoid explicit coercion by means of overloading.
<li><a href="http://cci.lbl.gov/staff/ralf_grosse-kunstleve.html">Ralf W.
Grosse-Kunstleve</a> contributed <a href="pickle.html">pickle support</a>
and numerous other small improvements. He's working on a way to allow
types exported by multiple modules to interact.
<li>The members of the boost mailing list and the Python community supplied
invaluable early feedback. In particular, Ron Clarke, Mark Evans, Anton
Gluck, Ralf W. Grosse-Kunstleve, Prabhu Ramachandran, and Barry Scott took
the brave step of trying to use py_cpp while it was still in early stages
of development.
<li>The members of the boost mailing list and the Python community
supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans,
Anton Gluck, Chuck Ingold, Prabhu Ramachandran, and Barry Scott took the
brave step of trying to use Boost.Python while it was still in early
stages of development.
<li>The development of py_cpp wouldn't have been
possible without the generous support of <a href="http://www.dragonsys.com/">Dragon Systems/Lernout and
Hauspie, Inc</a> who supported its development as an open-source project.
<li>The development of Boost.Python wouldn't have been possible without
the generous support of <a href="http://www.dragonsys.com/">Dragon
Systems/Lernout and Hauspie, Inc</a> who supported its development as an
open-source project.
</ul>
<h2>Table of Contents</h2>
@@ -105,10 +112,12 @@ among others.
<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
<li><a href="comparisons.html">Comparisons between Boost.Python and other
systems for extending Python</a>
<li><a href="example1.html">A Simple Example Using py_cpp</a>
<li><a href="example1.html">A Simple Example</a>
<li><a href="exporting_classes.html">Exporting Classes</a>
<li><a href="overriding.html">Overridable Virtual Functions</a>
@@ -120,92 +129,38 @@ among others.
<li><a href="under-the-hood.html">A Peek Under the Hood</a>
<li><a href="building.html">Building a Module with Py_cpp</a>
<li><a href="building.html">Building an Extension Module</a>
<li>Advanced Topics
<li><a href="pickle.html">Pickle Support</a>
<ol>
<li>class_builder&lt;&gt;
<li><a href="cross_module.html">Cross-Extension-Module Dependencies</a>
<li><a href="enums.html">enums</a>
<li><a href="enums.html">Wrapping Enums</a>
<li>References
<li><a href="pointers.html">Pointers and Smart Pointers</a>
<li><a href="pointers.html">Pointers and Smart Pointers</a>
<li>Built-in Python Types
<li>Other Extension Types
<li>Templates
</ol>
<li><a href="data_structures.txt">Internal Data Structures</a>
</ol>
<p>
More sophisticated examples 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...
Documentation is a major ongoing project; assistance is greatly
appreciated! In the meantime, useful examples of every Boost.Python feature should
be evident in the regression test files <code>test/comprehensive.[<a
href="../test/comprehensive.py">py</a>/<a
href="../test/comprehensive.hpp">hpp</a>/<a
href="../test/comprehensive.cpp">cpp</a>]</code>
<p>
Questions should be directed to <a href=
"http://www.egroups.com/list/boost">the boost mailing list</a>.
<h2>Naming Contest</h2>
"http://www.yahoogroups.com/list/boost">the boost mailing list</a>.
<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&lt;0.2wink&gt; 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 - <b>C</b>onvert <b>C</b>++ <b>
C</b>lasses to <b>P</b>ython
<li>
C<sup>3</sup>PO - <b>C</b>onvert <b>C</b>++
<b>C</b>lasses to <b>P</b>ython <b>
O</b>bjects
<li>
PALIN - <b>P</b>ython <b>
A</b>ugmented-<b>L</b>anguage <b>
IN</b>tegration
<li>
CLEESE - <b>C</b>++ <b>L</b>anguage <b>E</b>xtension <b>E</b>nvironment
<b>S</b>upremely <b>E</b>asy
<li>
JONES - <b>J</b>ust <b>O</b>bscenely <b>N</b>eat <b>E</b>xtension
<b>S</b>ystem
<li>
C-thru
<li>
SeamlessC
<li>
BorderCrossing
<li>
Perseus (because he solved a hairy problem involving snakes by using
reflection and was invisible most of the time).
</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>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
&copy; Copyright David Abrahams 2001. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &ldquo;as is&rdquo; without
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: Nov 26, 2000
Updated: Mar 6, 2001

View File

@@ -12,11 +12,11 @@
<h2>Inheritance in Python</h2>
<p>
Py_cpp extension classes support single and multiple-inheritance in
Python, just like regular Python classes. You can mix built-in Python
classes with py_cpp extension classes in a derived class' tuple of
bases. Whenever a py_cpp extension class is among the bases for a new
class in Python, the result is an extension class:
Boost.Python extension classes support single and multiple-inheritance in
Python, just like regular Python classes. You can arbitrarily mix
built-in Python classes with extension classes in a derived class'
tuple of bases. Whenever a Boost.Python extension class is among the bases for a
new class in Python, the result is an extension class:
<blockquote>
<pre>
&gt;&gt;&gt; class MyPythonClass:
@@ -37,7 +37,7 @@
<h2><a name="implicit_conversion">Reflecting C++ Inheritance Relationships</a></h2>
<p>
Py_cpp also allows us to represent C++ inheritance relationships so that
Boost.Python also allows us to represent C++ inheritance relationships so that
wrapped derived classes may be passed where values, pointers, or
references to a base class are expected as arguments. The
<code>declare_base</code> member function of
@@ -71,22 +71,22 @@ int get_derived_x(const Derived& d) {
return d.x;
}
<hr>
#include <boost/python/class_builder.hpp>
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
void initmy_module()
#include &lt;boost/python/class_builder.hpp&gt;
// namespace alias for code brevity
namespace python = boost::python;
BOOST_PYTHON_MODULE_INIT(my_module)
{
    try
    {
       boost::python::module_builder my_module("my_module");
       python::module_builder my_module("my_module");
       boost::python::class_builder&lt;Base&gt; base_class(my_module, "Base");
       base_class.def(boost::python::constructor&lt;void&gt;());
       python::class_builder&lt;Base&gt; base_class(my_module, "Base");
       base_class.def(python::constructor&lt;void&gt;());
       boost::python::class_builder&lt;Derived&gt; derived_class(my_module, "Derived");
       derived_class.def(boost::python::constructor&lt;void&gt;());
       python::class_builder&lt;Derived&gt; derived_class(my_module, "Derived");
       derived_class.def(python::constructor&lt;void&gt;());
<b>// Establish the inheritance relationship between Base and Derived
derived_class.declare_base(base_class);</b>
@@ -96,7 +96,7 @@ void initmy_module()
    }
    catch(...)
    {
       boost::python::handle_exception();    // Deal with the exception for Python
       python::handle_exception();    // Deal with the exception for Python
    }
}
</pre>
@@ -111,11 +111,19 @@ void initmy_module()
&gt;&gt;&gt; derived = Derived()
&gt;&gt;&gt; get_name(base)
'Base'
</pre><i>objects of wrapped class Derived may be passed where Base is expected</i><pre>
</pre>
</blockquote>
<i>objects of wrapped class Derived may be passed where Base is expected</i>
<blockquote>
<pre>
&gt;&gt;&gt; get_name(derived)
'Derived'
</pre><i>objects of wrapped class Derived can be passed where Derived is
expected but where type information has been lost.</i><pre>
</pre>
</blockquote>
<i>objects of wrapped class Derived can be passed where Derived is
expected but where type information has been lost.</i>
<blockquote>
<pre>
&gt;&gt;&gt; get_derived_x(derived_as_base())
-1
</pre>
@@ -135,12 +143,12 @@ struct Base2 {};
struct Derived2 { int f(); };
<hr>
...
   boost::python::class_builder&lt;Base&gt; base2_class(my_module, "Base2");
   base2_class.def(boost::python::constructor&lt;void&gt;());
   python::class_builder&lt;Base&gt; base2_class(my_module, "Base2");
   base2_class.def(python::constructor&lt;void&gt;());
   boost::python::class_builder&lt;Derived2&gt; derived2_class(my_module, "Derived2");
   derived2_class.def(boost::python::constructor&lt;void&gt;());
derived_class.declare_base(base_class, <b>boost::python::without_downcast</b>);
   python::class_builder&lt;Derived2&gt; derived2_class(my_module, "Derived2");
   derived2_class.def(python::constructor&lt;void&gt;());
derived_class.declare_base(base_class, <b>python::without_downcast</b>);
</pre>
</blockquote>
@@ -150,8 +158,8 @@ struct Derived2 { int f(); };
references, or values.
<p>
Next: <a href="special.html">Special Method and Operator Support</a>
Previous: <a href="overloading.html">Function Overloading</a>
Next: <a href="special.html">Special Method Names</a>
Up: <a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,

View File

@@ -29,7 +29,7 @@ private:
};
...
void initoverload_demo()
BOOST_PYTHON_MODULE_INIT(overload_demo)
{
    try
    {
@@ -113,18 +113,17 @@ namespace scope as Python member functions.
<h2>Overload Resolution</h2>
<p>
The function overload resolution mechanism in py_cpp works as
follows:
The function overload resolution mechanism works as follows:
<ul>
<li>Attribute lookup for extension classes proceeds in <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the
href="http://www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the
usual Python way</a> using a depth-first, left-to-right search. When a
class is found which has a matching attribute, only functions overloaded
in the context of that class are candidates for overload resolution. In
this sense, overload resolution mirrors the C++ mechanism, where a name
in a derived class &ldquo;hides&rdquo; all functions with the same name from a base
in a derived class ``hides'' all functions with the same name from a base
class.
<p>
@@ -133,24 +132,24 @@ namespace scope as Python member functions.
<code>def()</code>ed. The first function whose signature can be made to
match each argument passed is the one which is ultimately called.
This means in particular that you cannot overload the same function on
both &ldquo;<code>int</code>&rdquo; and &ldquo;<code>float</code>&rdquo; because Python
both ``<code>int</code>'' and ``<code>float</code>'' because Python
automatically converts either of the two types into the other one.
If the &ldquo;<code>float</code>&rdquo; overload is found first, it is used
also used for arguments of type &ldquo;<code>int</code>&rdquo; as well, and the
&ldquo;<code>int</code>&rdquo; version of the function is never invoked.
If the ``<code>float</code>'' overload is found first, it is used
also used for arguments of type ``<code>int</code>'' as well, and the
``<code>int</code>'' version of the function is never invoked.
</ul>
<p>
Prev: <a href="overriding.html">Overridable Virtual Functions</a>
Next: <a href="inheritance.html">Special Method Names</a>
Next: <a href="inheritance.html">Inheritance</a>
Previous: <a href="overriding.html">Overridable Virtual Functions</a>
Up: <a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
&copy; Copyright David Abrahams 2001. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &ldquo;as
is&rdquo; without express or implied warranty, and with no claim as to
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: Nov 26, 2000
Updated: Mar 6, 2001
</div>

View File

@@ -9,7 +9,7 @@
<h1>Overridable Virtual Functions</h1>
<p>
In the <a href="example1.html">previous example</a> we exposed a simple
In the <a href="exporting_classes.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 behave virtually <em>when called from C++</em>.
@@ -17,16 +17,17 @@
<h2><a name="overriding_example">Example</a></h2>
<p>In this example, it is assumed that <code>world::get()</code> is a virtual
<p>In this example, it is assumed that <code>hello::greet()</code> is a virtual
member function:
<blockquote><pre>
class world
class hello
{
public:
   world(int);
    virtual ~world();
    <b>virtual</b> std::string get() const { return "hi, world"; }
hello(const std::string&amp; country) { this-&gt;country = country; }
<b>virtual</b> std::string greet() const { return "Hello from " + country; }
    virtual ~hello(); // Good practice
...
};
</pre></blockquote>
@@ -37,21 +38,28 @@ class world
<ol>
<li><a name="derived_1">A</a> <code>PyObject*</code> data member that holds a
reference to the corresponding Python object.
<li><a name="derived_1">A</a> <code>PyObject*</code> data member (usually
called <tt>self</tt>) that holds a pointer to the Python object corresponding
to our C++ <tt>hello</tt> instance.
<li><a name="derived_2">A</a> constructor for each exposed constructor of the
base class which stores an additional initial <code>PyObject*</code> argument
in the data member described above.
<li><a name="derived_2">For</a> each exposed constructor of the
base class <tt>T</tt>, a constructor which takes the same parameters preceded by an initial
<code>PyObject*</code> argument. The initial argument should be stored in the <tt>self</tt> data
member described above.
<li>If the class being wrapped is ever returned <i>by
value</i> from a wrapped function, be sure you do the same for the
<tt>T</tt>'s copy constructor: you'll need a constructor taking arguments
<tt>(PyObject*,&nbsp;const&nbsp;T&amp;)</tt>.
<li><a name="derived_3">An</a> implementation of each virtual function you may
wish to override in Python which uses
<code>boost::python::callback&lt<i>return-type</i>&gt;::call_method()</code> to call
<tt>callback&lt</tt><i>return-type</i><tt>&gt;::call_method(self,&nbsp;&quot;</tt><i>name</i><tt>&quot;,&nbsp;</tt><i>args...</i><tt>)</tt> to call
the Python override.
<li><a name="derived_4">For</a> each non-pure virtual function meant to be
overridable from Python, a static member function (or a free function) taking
a reference or pointer to the base type as the first parameter and which
a reference or pointer to the <tt>T</tt> as the first parameter and which
forwards any additional parameters neccessary to the <i>default</i>
implementation of the virtual function. See also <a href="#private">this
note</a> if the base class virtual function is private.
@@ -59,52 +67,60 @@ class world
</ol>
<blockquote><pre>
struct world_callback : world
struct hello_callback : hello
{
world_callback(PyObject* self, int x) // <a href="#derived_2">2</a>
: world(x),
m_self(self) {}
// hello constructor storing initial self_ parameter
hello_callback(PyObject* self_, const std::string&amp; x) // <a href="#derived_2">2</a>
: hello(x), self(self_) {}
std::string get() const // <a href="#derived_3">3</a>
{ return boost::python::callback&lt;std::string&gt;::call_method(m_self, "get"); }
// In case hello is returned by-value from a wrapped function
hello_callback(PyObject* self_, const hello&amp; x) // <a href="#derived_3">3</a>
: hello(x), self(self_) {}
static std::string <a name= "default_implementation">default_get</a>(const hello::world& self) const // <a href="#derived_4">4</a>
{ return self.world::get(); }
// Override greet to call back into Python
std::string greet() const // <a href="#derived_4">4</a>
{ return boost::python::callback&lt;std::string&gt;::call_method(self, "greet"); }
// Supplies the default implementation of greet
static std::string <a name= "default_implementation">default_greet</a>(const hello& self_) const // <a href="#derived_5">5</a>
{ return self_.hello::greet(); }
private:
PyObject* m_self; // <a href="#derived_1">1</a>
PyObject* self; // <a href="#derived_1">1</a>
};
</pre></blockquote>
<p>
Finally, we add <code>world_callback</code> to the <code>
class_builder&lt;&gt;</code> declaration in our module initialization
function, and when we define the function, we must tell py_cpp about the default
Finally, we add <tt>hello_callback</tt> to the <tt>
class_builder&lt;&gt;</tt> declaration in our module initialization
function, and when we define the function, we must tell Boost.Python about the default
implementation:
<blockquote><pre>
// Create the <a name=
"world_class">Python type object</a> for our extension class
boost::python::class_builder&lt;hello::world<strong>,world_callback&gt;</strong> world_class(hello, "world");
"hello_class">Python type object</a> for our extension class
boost::python::class_builder&lt;hello<strong>,hello_callback&gt;</strong> hello_class(hello, "hello");
// Add a virtual member function
world_class.def(&amp;world::get, "get", &amp;<b>world_callback::default_get</b>);
hello_class.def(&amp;hello::greet, "greet", &amp;<b>hello_callback::default_greet</b>);
</pre></blockquote>
<p>
Now our subclass of <code>hello.world</code> behaves as expected:
Now our Python subclass of <tt>hello</tt> behaves as expected:
<blockquote><pre>
&gt;&gt;&gt; class my_subclass(hello.world):
... def get(self):
... return 'hello, world'
&gt;&gt;&gt; class wordy(hello):
... def greet(self):
... return hello.greet(self) + ', where the weather is fine'
...
&gt;&gt;&gt; hello.length(my_subclass())
12
&gt;&gt;&gt; hi2 = wordy('Florida')
&gt;&gt;&gt; hi2.greet()
'Hello from Florida, where the weather is fine'
&gt;&gt;&gt; invite(hi2)
'Hello from Florida, where the weather is fine! Please come soon!'
</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
inside of <tt>hello</tt>." One of the goals of Boost.Python 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. To unintrusively hook into the virtual functions so that a Python
@@ -117,32 +133,29 @@ world_class.def(&amp;world::get, "get", &amp;<b>world_callback::default_get</b>)
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>extension_class&lt;&gt;</code> instance
<tt>def()</tt> on the <tt>extension_class&lt;&gt;</tt> 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,
<tt>AttributeError</tt> 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> int pure(int) = 0;
int calls_pure(int x) { return pure(x) + 1000; }
};
struct baz_callback {
int pure(int x) { boost::python::callback&lt;int&gt;::call_method(m_self, "pure", x); }
};
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
initfoobar()
BOOST_PYTHON_MODULE_INIT(foobar)
{
try
{
boost::python::module_builder foobar("foobar");
boost::python::class_builder&lt;baz,baz_callback&gt; baz_class("baz");
baz_class.def(&amp;baz::pure, "pure");
baz_class.def(&amp;baz::calls_pure, "calls_pure");
}
catch(...)
{
@@ -161,12 +174,18 @@ initfoobar()
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: pure
&gt;&gt;&gt; x.calls_pure(1)
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: pure
&gt;&gt;&gt; class mumble(baz):
... def pure(self, x): return x + 1
...
&gt;&gt;&gt; y = mumble()
&gt;&gt;&gt; y.pure(99)
100
&gt;&gt;&gt; y.calls_pure(99)
1100
</pre></blockquote>
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
@@ -180,16 +199,17 @@ this limited way without breaking binary compatibility (though it will certainly
break the <a
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
<hr>
<p>
Prev: <a href="example1.html">A Simple Example Using py_cpp</a> Next: <a
href="overloading.html">Function Overloading</a> Up: <a href=
"index.html">Top</a>
Next: <a href="overloading.html">Function Overloading</a>
Previous: <a href="exporting_classes.html">Exporting Classes</a>
Up: <a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
&copy; Copyright David Abrahams 2001. 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: Nov 26, 2000
Updated: Mar 6, 2001

272
doc/pickle.html Normal file
View File

@@ -0,0 +1,272 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>Boost.Python Pickle Support</title>
<div>
<img src="../../../c++boost.gif"
alt="c++boost.gif (8819 bytes)"
align="center"
width="277" height="86">
<hr>
<h1>Boost.Python Pickle Support</h1>
Pickle is a Python module for object serialization, also known
as persistence, marshalling, or flattening.
<p>
It is often necessary to save and restore the contents of an object to
a file. One approach to this problem is to write a pair of functions
that read and write data from a file in a special format. A powerful
alternative approach is to use Python's pickle module. Exploiting
Python's ability for introspection, the pickle module recursively
converts nearly arbitrary Python objects into a stream of bytes that
can be written to a file.
<p>
The Boost Python Library supports the pickle module by emulating the
interface implemented by Jim Fulton's ExtensionClass module that is
included in the
<a href="http://www.zope.org/"
>ZOPE</a>
distribution.
This interface is similar to that for regular Python classes as
described in detail in the
<a href="http://www.python.org/doc/current/lib/module-pickle.html"
>Python Library Reference for pickle.</a>
<hr>
<h2>The Boost.Python Pickle Interface</h2>
At the user level, the Boost.Python pickle interface involves three special
methods:
<dl>
<dt>
<strong><tt>__getinitargs__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is pickled, the
pickler tests if the instance has a <tt>__getinitargs__</tt> method.
This method must return a Python tuple (it is most convenient to use
a boost::python::tuple). When the instance is restored by the
unpickler, the contents of this tuple are used as the arguments for
the class constructor.
<p>
If <tt>__getinitargs__</tt> is not defined, the class constructor
will be called without arguments.
<p>
<dt>
<strong><tt>__getstate__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is pickled, the
pickler tests if the instance has a <tt>__getstate__</tt> method.
This method should return a Python object representing the state of
the instance.
<p>
If <tt>__getstate__</tt> is not defined, the instance's
<tt>__dict__</tt> is pickled (if it is not empty).
<p>
<dt>
<strong><tt>__setstate__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is restored by the
unpickler, it is first constructed using the result of
<tt>__getinitargs__</tt> as arguments (see above). Subsequently the
unpickler tests if the new instance has a <tt>__setstate__</tt>
method. If so, this method is called with the result of
<tt>__getstate__</tt> (a Python object) as the argument.
<p>
If <tt>__setstate__</tt> is not defined, the result of
<tt>__getstate__</tt> must be a Python dictionary. The items of this
dictionary are added to the instance's <tt>__dict__</tt>.
</dl>
If both <tt>__getstate__</tt> and <tt>__setstate__</tt> are defined,
the Python object returned by <tt>__getstate__</tt> need not be a
dictionary. The <tt>__getstate__</tt> and <tt>__setstate__</tt> methods
can do what they want.
<hr>
<h2>Pitfalls and Safety Guards</h2>
In Boost.Python extension modules with many extension classes,
providing complete pickle support for all classes would be a
significant overhead. In general complete pickle support should only be
implemented for extension classes that will eventually be pickled.
However, the author of a Boost.Python extension module might not
anticipate correctly which classes need support for pickle.
Unfortunately, the pickle protocol described above has two important
pitfalls that the end user of a Boost.Python extension module might not
be aware of:
<dl>
<dt>
<strong>Pitfall 1:</strong>
Both <tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined.
<dd>
In this situation the unpickler calls the class constructor without
arguments and then adds the <tt>__dict__</tt> that was pickled by
default to that of the new instance.
<p>
However, most C++ classes wrapped with Boost.Python will have member
data that are not restored correctly by this procedure. To alert the
user to this problem, a safety guard is provided. If both
<tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined,
Boost.Python tests if the class has an attribute
<tt>__dict_defines_state__</tt>. An exception is raised if this
attribute is not defined:
<pre>
RuntimeError: Incomplete pickle support (__dict_defines_state__ not set)
</pre>
In the rare cases where this is not the desired behavior, the safety
guard can deliberately be disabled. The corresponding C++ code for
this is, e.g.:
<pre>
class_builder&lt;your_class&gt; py_your_class(your_module, "your_class");
py_your_class.dict_defines_state();
</pre>
It is also possible to override the safety guard at the Python level.
E.g.:
<pre>
import your_bpl_module
class your_class(your_bpl_module.your_class):
__dict_defines_state__ = 1
</pre>
<p>
<dt>
<strong>Pitfall 2:</strong>
<tt>__getstate__</tt> is defined and the instance's <tt>__dict__</tt> is not empty.
<dd>
The author of a Boost.Python extension class might provide a
<tt>__getstate__</tt> method without considering the possibilities
that:
<p>
<ul>
<li>
his class is used in Python as a base class. Most likely the
<tt>__dict__</tt> of instances of the derived class needs to be
pickled in order to restore the instances correctly.
<p>
<li>
the user adds items to the instance's <tt>__dict__</tt> directly.
Again, the <tt>__dict__</tt> of the instance then needs to be
pickled.
</ul>
<p>
To alert the user to this highly unobvious problem, a safety guard is
provided. If <tt>__getstate__</tt> is defined and the instance's
<tt>__dict__</tt> is not empty, Boost.Python tests if the class has
an attribute <tt>__getstate_manages_dict__</tt>. An exception is
raised if this attribute is not defined:
<pre>
RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
</pre>
To resolve this problem, it should first be established that the
<tt>__getstate__</tt> and <tt>__setstate__</tt> methods manage the
instances's <tt>__dict__</tt> correctly. Note that this can be done
both at the C++ and the Python level. Finally, the safety guard
should intentionally be overridden. E.g. in C++:
<pre>
class_builder&lt;your_class&gt; py_your_class(your_module, "your_class");
py_your_class.getstate_manages_dict();
</pre>
In Python:
<pre>
import your_bpl_module
class your_class(your_bpl_module.your_class):
__getstate_manages_dict__ = 1
def __getstate__(self):
# your code here
def __setstate__(self, state):
# your code here
</pre>
</dl>
<hr>
<h2>Practical Advice</h2>
<ul>
<li>
Avoid using <tt>__getstate__</tt> if the instance can also be
reconstructed by way of <tt>__getinitargs__</tt>. This automatically
avoids Pitfall 2.
<p>
<li>
If <tt>__getstate__</tt> is required, include the instance's
<tt>__dict__</tt> in the Python object that is returned.
</ul>
<hr>
<h2>Examples</h2>
There are three files in <tt>boost/libs/python/example</tt> that
show how so provide pickle support.
<h3><a href="../example/pickle1.cpp"><tt>pickle1.cpp</tt></a></h3>
The C++ class in this example can be fully restored by passing the
appropriate argument to the constructor. Therefore it is sufficient
to define the pickle interface method <tt>__getinitargs__</tt>.
<h3><a href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a></h3>
The C++ class in this example contains member data that cannot be
restored by any of the constructors. Therefore it is necessary to
provide the <tt>__getstate__</tt>/<tt>__setstate__</tt> pair of
pickle interface methods.
<p>
For simplicity, the <tt>__dict__</tt> is not included in the result
of <tt>__getstate__</tt>. This is not generally recommended, but a
valid approach if it is anticipated that the object's
<tt>__dict__</tt> will always be empty. Note that the safety guards
will catch the cases where this assumption is violated.
<h3><a href="../example/pickle3.cpp"><tt>pickle3.cpp</tt></a></h3>
This example is similar to <a
href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a>. However, the
object's <tt>__dict__</tt> is included in the result of
<tt>__getstate__</tt>. This requires more code but is unavoidable
if the object's <tt>__dict__</tt> is not always empty.
<hr>
&copy; Copyright Ralf W. Grosse-Kunstleve 2001. 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: March 21, 2001
</div>

View File

@@ -13,7 +13,7 @@
<p>
In general, raw pointers passed to or returned from functions are problematic
for py_cpp because pointers have too many potential meanings. Is it an iterator?
for Boost.Python because pointers have too many potential meanings. Is it an iterator?
A pointer to a single element? An array? When used as a return value, is the
caller expected to manage (delete) the pointed-to object or is the pointer
really just a reference? If the latter, what happens to Python references to the
@@ -34,12 +34,10 @@ converted from/to Python strings.
<h3>Can you avoid the problem?</h3>
<p>My first piece of advice to anyone with a case not covered above is
&ldquo;find a way to avoid the problem.&rdquo; For example, if you have just one
or two functions returning a pointer to a single (not an array of) <code>const
T*</code> for some wrapped <code>T</code>, you may be able to write a &ldquo;thin
converting wrapper&rdquo; over those two functions as follows (Since py_cpp
converts <code>const T&</code> values <code>to_python</code> by copying the T
into a new extension instance, Foo must have a public copy constructor):
``find a way to avoid the problem.'' For example, if you have just one
or two functions that return a pointer to an individual <code>const
T</code>, and <code>T</code> is a wrapped class, you may be able to write a ``thin
converting wrapper'' over those two functions as follows:
<blockquote><pre>
const Foo* f(); // original function
@@ -47,6 +45,10 @@ const Foo& f_wrapper() { return *f(); }
...
my_module.def(f_wrapper, "f");
</pre></blockquote>
<p>
Foo must have a public copy constructor for this technique to work, since Boost.Python
converts <code>const T&</code> values <code>to_python</code> by copying the <code>T</code>
value into a new extension instance.
<h2>Dealing with the problem</h2>
@@ -83,12 +85,12 @@ code before the last Python reference to it disappears:
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
PyObject* to_python(Foo* p)
{
return boost::python::PyExtensionClassConverters<Foo>::ptr_to_python(p);
return boost::python::python_extension_class_converters&ltFoo&gt::ptr_to_python(p);
}
PyObject* to_python(const Foo* p)
{
return to_python(const_cast<Foo*>(p));
return to_python(const_cast&lt;Foo*&gt;(p));
}
BOOST_PYTHON_END_CONVERSION_NAMESPACE
</pre></blockquote>
@@ -118,7 +120,7 @@ return value. You can handle this case by returning a Python tuple:
typedef unsigned ErrorCode;
const char* f(int* in_out_x); // original function
...
#include <boost/python/objects.hpp>
#include &lt;boost/python/objects.hpp&gt;
const boost::python::tuple f_wrapper(int in_x) {
const char* s = f(in_x);
return boost::python::tuple(s, in_x);
@@ -131,8 +133,9 @@ my_module.def(f_wrapper, "f");
&gt;&gt;&gt; str,out_x = f(3)
</pre></blockquote>
<p>
Previous: <a href="enums.html">Enums</a>
Up: <a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright

View File

@@ -1,11 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<title>
Special Method and Operator Support
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center" src=
<img width="277" height="86" id="_x0000_i1025" align="middle" src=
"../../../c++boost.gif" alt="c++boost.gif (8819 bytes)">Special Method and
Operator Support
</h1>
@@ -13,8 +12,8 @@
Overview
</h2>
<p>
Py_cpp supports all of the standard <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
Boost.Python supports all of the standard <a href=
"http://www.python.org/doc/current/ref/specialnames.html">
special method names</a> supported by real Python class instances <em>
except</em> <code>__complex__</code> (more on the reasons <a href=
"#reasons">below</a>). In addition, it can quickly and easily expose
@@ -34,19 +33,24 @@
Python provides a number of special operators for basic customization of a
class. Only a brief description is provided below; more complete
documentation can be found <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/customization.html">here</a>.
href="http://www.python.org/doc/current/ref/customization.html">here</a>.
<dl>
<dt>
<b><tt class='method'>__init__</tt></b>(<i>self</i>)
<dd>
Initialize the class instance. For extension classes not subclassed in
Python, this is provided by the
<code>boost::python::constructor<...>()</code> construct and should <i>not</i> be explicitly <code>def</code>ed.
Python, <code> __init__</code> is defined by
<pre> my_class.def(boost::python::constructor<...>())</pre>
(see section <a href="example1.html">"A Simple Example Using Boost.Python"</a>).<p>
<dt>
<b><tt class='method'>__del__</tt></b>(<i>self</i>)
<dd>
Called when the extension instance is about to be destroyed.
Called when the extension instance is about to be destroyed. For extension classes
not subclassed in Python, <code> __del__</code> is always defined automatically by
means of the class' destructor.
<dt>
<b><tt class='method'>__repr__</tt></b>(<i>self</i>)
<dd>
@@ -78,7 +82,7 @@
<dt>
<b><tt class='method'>__call__</tt></b> (<var>self</var><big>[</big><var>, args...</var><big>]</big>)
<dd>
Called when the instance is &ldquo;called&rdquo; as a function; if this method
Called when the instance is ``called'' as a function; if this method
is defined, <code><var>x</var>(arg1, arg2, ...)</code> is a shorthand for
<code><var>x</var>.__call__(arg1, arg2, ...)</code>.
</dl>
@@ -100,7 +104,7 @@ std::string to_string(Foo const&amp; f)
boost::python::class_builder&lt;Foo&gt; foo_class(my_module, "Foo");
foo_class.def(&amp;to_string, "__str__");
</pre></blockquote>
Note that py_cpp also supports <em>automatic wrapping</em> of
Note that Boost.Python also supports <em>automatic wrapping</em> of
<code>__str__</code> and <code>__cmp__</code>. This is explained in the <a
href="#numeric">next section</a> and the <a href="#numeric_table">Table of
Automatically Wrapped Methods</a>.
@@ -110,10 +114,10 @@ foo_class.def(&amp;to_string, "__str__");
<p>
Numeric operators can be exposed manually, by <code>def</code>ing C++
[member] functions that support the standard Python <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">numeric
protocols</a>. This is the basic same technique used to expose
href="http://www.python.org/doc/current/ref/numeric-types.html">numeric
protocols</a>. This is the same basic technique used to expose
<code>to_string()</code> as <code>__str__()</code> above, and is <a
href="#numeric_manual">covered in detail below</a>. Py_cpp also supports
href="#numeric_manual">covered in detail below</a>. Boost.Python also supports
<i>automatic wrapping</i> of numeric operators whenever they have already
been defined in C++.
@@ -121,7 +125,7 @@ foo_class.def(&amp;to_string, "__str__");
<p>
Supose we wanted to expose a C++ class
<code>BigNum</code> which supports addition, so that we can write (in C++):
<code>BigNum</code> which supports addition. That is, in C++ we can write:
<blockquote><pre>
BigNum a, b, c;
...
@@ -143,7 +147,7 @@ bignum_class.def(boost::python::operators&lt;boost::python::op_add&gt;());
Since BigNum also supports subtraction, multiplication, and division, we
want to export those also. This can be done in a single command by
&ldquo;or&rdquo;ing the operator identifiers together (a complete list of these
``or''ing the operator identifiers together (a complete list of these
identifiers and the corresponding operators can be found in the <a href=
"#numeric_table">Table of Automatically Wrapped Methods</a>):
<blockquote><pre>
@@ -170,7 +174,7 @@ a = i + b;
bignum_class.def(boost::python::operators&lt;boost::python::op_add&gt;(), boost::python::right_operand&lt;int&gt;());
bignum_class.def(boost::python::operators&lt;boost::python::op_add&gt;(), boost::python::left_operand&lt;int&gt;());
</pre></blockquote>
Py_cpp uses overloading to register several variants of the same
Boost.Python uses overloading to register several variants of the same
operation (more on this in the context of <a href="#coercion">
coercion</a>). Again, several operators can be exported at once:
<blockquote><pre>
@@ -181,7 +185,7 @@ bignum_class.def(boost::python::operators&lt;(boost::python::op_sub | boost::pyt
</pre></blockquote>
The type of the operand not mentioned is taken from the class being wrapped. In
our example, the class object is <code>bignum_class</code>, and thus the
other operand's type is &ldquo;<code>BigNum const&amp;</code>&rdquo;. You can override
other operand's type is ``<code>BigNum const&amp;</code>''. You can override
this default by explicitly specifying a type in the <code>
operators</code> template:
<blockquote><pre>
@@ -189,15 +193,18 @@ bignum_class.def(boost::python::operators&lt;boost::python::op_add, BigNum&gt;()
</pre></blockquote>
<p>
Note that automatic wrapping uses the <em>expression</em>
&ldquo;<code>left + right</code>&rdquo; and can be used uniformly
``<code>left + right</code>'' and can be used uniformly
regardless of whether the C++ operators are supplied as free functions
<blockquote><pre>
<blockquote><pre>
BigNum operator+(BigNum, BigNum)
</pre></blockquote>
or as member
functions <blockquote><pre>
or as member functions
<blockquote><pre>
BigNum::operator+(BigNum).
</blockquote></pre>
</pre></blockquote>
<p>
For the Python built-in functions <code>pow()</code> and
@@ -218,8 +225,7 @@ namespace boost { namespace python {
<p>
In some cases, automatic wrapping of operators may be impossible or
undesirable. Suppose, for example, that the modulo operation for BigNums
is defined by a set of functions <code>mod()</code> (for automatic
wrapping, we would need <code>operator%()</code>):
is defined by a set of functions called <code>mod()</code>:
<blockquote><pre>
BigNum mod(BigNum const&amp; left, BigNum const&amp; right);
@@ -228,8 +234,9 @@ BigNum mod(int left, BigNum const&amp; right);
</pre></blockquote>
<p>
In order to create the Python operator "__mod__" from these functions, we
have to wrap them manually:
For automatic wrapping of the modulo function, <code>operator%()</code> would be needed.
Therefore, the <code>mod()</code>-functions must be wrapped manually. That is, we have
to export them explicitly with the Python special name "__mod__":
<blockquote><pre>
bignum_class.def((BigNum (*)(BigNum const&amp;, BigNum const&amp;))&amp;mod, "__mod__");
@@ -237,8 +244,8 @@ bignum_class.def((BigNum (*)(BigNum const&amp;, int))&amp;mod, "__mod__");
</pre></blockquote>
<p>
The third form (with <code>int</code> as left operand) cannot be wrapped
this way. We must first create a function <code>rmod()</code> with the
The third form of <code>mod()</code> (with <code>int</code> as left operand) cannot
be wrapped directly. We must first create a function <code>rmod()</code> with the
operands reversed:
<blockquote><pre>
@@ -248,7 +255,7 @@ BigNum rmod(BigNum const&amp; right, int left)
}
</pre></blockquote>
This function must be wrapped under the name "__rmod__":
This function must be wrapped under the name "__rmod__" (standing for "reverse mod"):
<blockquote><pre>
bignum_class.def(&amp;rmod, "__rmod__");
@@ -261,9 +268,9 @@ bignum_class.def(&amp;rmod, "__rmod__");
<p>
Automatic and manual wrapping can be mixed arbitrarily. Note that you
cannot overload the same operator for a given extension class on both
&ldquo;<code>int</code>&rdquo; and &ldquo;<code>float</code>&rdquo;, because Python implicitly
``<code>int</code>'' and ``<code>float</code>'', because Python implicitly
converts these types into each other. Thus, the overloaded variant
found first (be it &ldquo;<code>int</code>&ldquo; or &ldquo;<code>float</code>&rdquo;) will be
found first (be it ``<code>int</code>`` or ``<code>float</code>'') will be
used for either of the two types.
<h3><a name="coercion">Coercion</a></h3>
@@ -271,18 +278,18 @@ bignum_class.def(&amp;rmod, "__rmod__");
Plain Python can only execute operators with identical types on the left
and right hand side. If it encounters an expression where the types of
the left and right operand differ, it tries to coerce these type to a
the left and right operand differ, it tries to coerce these types to a
common type before invoking the actual operator. Implementing good
coercion functions can be difficult if many type combinations must be
supported.
<p>
Py_cpp solves this problem the same way that C++ does: with <em><a
Boost.Python solves this problem the same way that C++ does: with <em><a
href="overloading.html">overloading</a></em>. This technique drastically
simplifies the code neccessary to support operators: you just register
operators for all desired type combinations, and py_cpp automatically
operators for all desired type combinations, and Boost.Python automatically
ensures that the correct function is called in each case; there is no
need for user-defined coercion functions. To enable operator
overloading, py_cpp provides a standard coercion which is <em>implicitly
overloading, Boost.Python provides a standard coercion which is <em>implicitly
registered</em> whenever automatic operator wrapping is used.
<p>
If you wrap all operator functions manually, but still want to use
@@ -295,7 +302,7 @@ bignum_class.def_standard_coerce();
</pre></blockquote>
If you encounter a situation where you absolutely need a customized
coercion, you can overload the "__coerce__" operator itself. The signature
coercion, you can still define the "__coerce__" operator manually. The signature
of a coercion function should look like one of the following (the first is
the safest):
@@ -310,13 +317,22 @@ PyObject* custom_coerce(PyObject* left, PyObject* right);
converted to the same type. Such a function is wrapped as usual:
<blockquote><pre>
// this must be called before any use of automatic operator
// wrapping or a call to some_class.def_standard_coerce()
some_class.def(&amp;custom_coerce, "__coerce__");
</pre></blockquote>
Note that the later use of automatic operator wrapping on a
<code>class_builder</code> or a call to
&ldquo;<code>some_class.def_standard_coerce()</code>&rdquo; will cause any
custom coercion function to be replaced by the standard one.
Note that the standard coercion (defined by use of automatic
operator wrapping on a <code>class_builder</code> or a call to
<code>class_builder::def_standard_coerce()</code>) will never be applied if
a custom coercion function has been registered. Therefore, in
your coercion function you should call
<blockquote><pre>
boost::python::standard_coerce(left, right);
</pre></blockquote>
for all cases that you don't want to handle yourself.
<h3><a name="ternary_pow">The Ternary <code>pow()</code> Operator</a></h3>
@@ -330,7 +346,7 @@ some_class.def(&amp;custom_coerce, "__coerce__");
this is done as usual:
<blockquote><pre>
BigNum power(BigNum const&amp; first, BigNum const&amp; second, BigNum const&amp; module);
BigNum power(BigNum const&amp; first, BigNum const&amp; second, BigNum const&amp; modulus);
typedef BigNum (ternary_function1)(const BigNum&amp;, const BigNum&amp;, const BigNum&amp;);
...
bignum_class.def((ternary_function1)&amp;power, "__pow__");
@@ -353,19 +369,19 @@ bignum_class.def((ternary_function2)&amp;power, "__pow__");
</pre></blockquote>
In the second variant, however, <code>BigNum</code> appears only as second
argument, and in the last one it is the third argument. These functions
must be presented to py_cpp such that that the <code>BigNum</code>
argument, and in the last one it's the third argument. These functions
must be presented to Boost.Python such that that the <code>BigNum</code>
argument appears in first position:
<blockquote><pre>
BigNum rpower(BigNum const&amp; second, int first, int modulus)
{
return power(first, second, third);
return power(first, second, modulus);
}
BigNum rrpower(BigNum const&amp; third, int first, int second)
BigNum rrpower(BigNum const&amp; modulus, int first, int second)
{
return power(first, second, third);
return power(first, second, modulus);
}
</pre></blockquote>
@@ -381,8 +397,8 @@ Note that "__rrpow__" is an extension not present in plain Python.
<h2><a name="numeric_table">Table of Automatically Wrapped Methods</a></h2>
<p>
Py_cpp can automatically wrap the following <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
Boost.Python can automatically wrap the following <a href=
"http://www.python.org/doc/current/ref/specialnames.html">
special methods</a>:
<p>
@@ -630,15 +646,16 @@ Note that "__rrpow__" is an extension not present in plain Python.
to Python's iteration and access protocols. These protocols differ
considerably from the ones found in C++. For example, Python's typical
iteration idiom looks like
<blockquote><pre>
for i in S:
</blockquote></pre>
</pre></blockquote>
while in C++ one writes
while in C++ one writes
<blockquote><pre>
for (iterator i = S.begin(), end = S.end(); i != end)
</blockquote></pre>
for (iterator i = S.begin(), end = S.end(); i != end; ++i)
</pre></blockquote>
<p>One could try to wrap C++ iterators in order to carry the C++ idiom into
Python. However, this does not work very well because
@@ -655,12 +672,12 @@ for (iterator i = S.begin(), end = S.end(); i != end)
<p>
It is a better idea to support the standard <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/sequence-types.html">Python
href="http://www.python.org/doc/current/ref/sequence-types.html">Python
sequence and mapping protocols</a> for your wrapped containers. These
operators have to be wrapped manually because there are no corresponding
C++ operators that could be used for automatic wrapping. The Python
documentation lists the relevant <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/sequence-types.html">
"http://www.python.org/doc/current/ref/sequence-types.html">
container operators</a>. In particular, expose __getitem__, __setitem__
and remember to raise the appropriate Python exceptions
(<code>PyExc_IndexError</code> for sequences,
@@ -689,7 +706,7 @@ void throw_key_error_if_end(
// Define some simple wrapper functions which match the Python protocol
// for __getitem__, __setitem__, and __delitem__. Just as in Python, a
// free function with a &ldquo;self&rdquo; first parameter makes a fine class method.
// free function with a ``self'' first parameter makes a fine class method.
const std::string&amp; get_item(const StringMap&amp; self, std::size_t key)
{
@@ -755,13 +772,13 @@ KeyError: 2
<h2><a name="getter_setter">Customized Attribute Access</a></h2>
<p>
Just like built-in Python classes, py_cpp extension classes support <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/attribute-access.html">special
Just like built-in Python classes, Boost.Python extension classes support <a
href="http://www.python.org/doc/current/ref/attribute-access.html">special
the usual attribute access methods</a> <code>__getattr__</code>,
<code>__setattr__</code>, and <code>__delattr__</code>.
Because writing these functions can
be tedious in the common case where the attributes being accessed are
known statically, py_cpp checks the special names
known statically, Boost.Python checks the special names
<ul>
<li>
@@ -774,10 +791,10 @@ KeyError: 2
to provide functional access to the attribute <em>&lt;name&gt;</em>. This
facility can be used from C++ or entirely from Python. For example, the
following shows how we can implement a &ldquo;computed attribute&rdquo; in Python:
following shows how we can implement a ``computed attribute'' in Python:
<blockquote>
<pre>
&gt;&gt;&gt; class Range(AnyPy_cppExtensionClass):
&gt;&gt;&gt; class Range(AnyBoost.PythonExtensionClass):
... def __init__(self, start, end):
... self.start = start
... self.end = end
@@ -793,7 +810,7 @@ KeyError: 2
Direct Access to Data Members
</h4>
<p>
Py_cpp uses the special <code>
Boost.Python uses the special <code>
__xxxattr__<em>&lt;name&gt;</em>__</code> functionality described above
to allow direct access to data members through the following special
functions on <code>class_builder&lt;&gt;</code> and <code>
@@ -873,14 +890,14 @@ if (PyInstance_Check(r)) { ...
</pre>
</blockquote>
<p>
Previous: <a href="inheritance.html">Inheritance</a> Next: <a href=
"under-the-hood.html">A Peek Under the Hood</a> Up: <a href=
"index.html">Top</a>
Next: <a href="under-the-hood.html">A Peek Under the Hood</a>
Previous: <a href="inheritance.html">Inheritance</a>
Up: <a href= "index.html">Top</a>
<p>
&copy; Copyright David Abrahams and Ullrich K&ouml;the 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 &ldquo;as is&rdquo; without express or implied
document is provided ``as is'' without express or implied
warranty, and with no claim as to its suitability for any purpose.
<p>
Updated: Nov 26, 2000

View File

@@ -1,26 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
The Title Of This Page
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">The Title Of This
Page
</h1>
<p>
<p>
Prev: <a href="prev.html">Previous</a>
Next: <a href="next.html">Next</a>
Up: <a href="index.html">Top</a>
<p>
&copy; 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: Nov 26, 2000
</div>

View File

@@ -22,7 +22,7 @@
"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
Boost.Python 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
@@ -48,8 +48,8 @@
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>
Next: <a href="building.html">Building a Module with Py_cpp</a>
Next: <a href="building.html">Building a Module with Boost.Python</a>
Previous: <a href="special.html">Special Method and Operator Support</a>
Up: <a href="index.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,