diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-06-25 22:59:01 +0000 |
---|---|---|
committer | <> | 2013-09-27 11:49:28 +0000 |
commit | 8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch) | |
tree | c09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/python/doc/v2/callbacks.html | |
download | boost-tarball-baserock/morph.tar.gz |
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/python/doc/v2/callbacks.html')
-rw-r--r-- | libs/python/doc/v2/callbacks.html | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/libs/python/doc/v2/callbacks.html b/libs/python/doc/v2/callbacks.html new file mode 100644 index 000000000..4e91befad --- /dev/null +++ b/libs/python/doc/v2/callbacks.html @@ -0,0 +1,254 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Calling Python Functions and Methods</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Calling Python Functions and Methods</h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#argument_handling">Argument Handling</a></dt> + + <dt><a href="#result_handling">Result Handling</a></dt> + + <dt><a href="#result_handling">Rationale</a></dt> + </dl> + <hr> + + <h2><a name="introduction">Introduction</a></h2> + The simplest way to call a Python function from C++, given an <code><a + href="object.html#object-spec">object</a></code> instance <code>f</code> + holding the function, is simply to invoke its function call operator. +<pre> +f("tea", 4, 2) // In Python: f('tea', 4, 2) +</pre> + And of course, a method of an <code><a href= + "object.html#object-spec">object</a></code> instance <code>x</code> can + be invoked by using the function-call operator of the corresponding + attribute: +<pre> +x.attr("tea")(4, 2); // In Python: x.tea(4, 2) +</pre> + + <p>If you don't have an <code>object</code> instance, Boost.Python + provides two families of function templates, <code><a href= + "call.html#call-spec">call</a></code> and <code><a href= + "call_method.html#call_method-spec">call_method</a></code>, for invoking + Python functions and methods respectively on <code>PyObject*</code>s. The + interface for calling a Python function object (or any Python callable + object) looks like:</p> +<pre> +call<ResultType>(callable_object, a1, a2... a<i>N</i>); +</pre> + Calling a method of a Python object is similarly easy: +<pre> +call_method<ResultType>(self_object, "<i>method-name</i>", a1, a2... a<i>N</i>); +</pre> + This comparitively low-level interface is the one you'll use when + implementing C++ virtual functions that can be overridden in Python. + + <h2><a name="argument_handling">Argument Handling</a></h2> + + <p>Arguments are converted to Python according to their type. By default, + the arguments <code>a1</code>...<code>a<i>N</i></code> are copied into + new Python objects, but this behavior can be overridden by the use of + <code><a href="ptr.html#ptr-spec">ptr()</a></code> and <a href= + "../../../bind/ref.html">ref()</a>:</p> +<pre> +class X : boost::noncopyable +{ + ... +}; + +void apply(PyObject* callable, X& x) +{ + // Invoke callable, passing a Python object which holds a reference to x + boost::python::call<void>(callable, boost::ref(x)); +} +</pre> + In the table below, <code><b>x</b></code> denotes the actual argument + object and <code><b>cv</b></code> denotes an optional + <i>cv-qualification</i>: "<code>const</code>", "<code>volatile</code>", + or "<code>const volatile</code>". + + <table border="1" summary="class_ template parameters"> + <tr> + <th>Argument Type</th> + + <th>Behavior</th> + </tr> + + <tr> + <td><code>T cv&</code><br> + <code>T cv</code></td> + + <td>The Python argument is created by the same means used for the + return value of a wrapped C++ function returning <code>T</code>. When + <code>T</code> is a class type, that normally means <code>*x</code> + is copy-constructed into the new Python object.</td> + </tr> + + <tr> + <td><code>T*</code></td> + + <td>If <code>x == 0</code>, the Python argument will be + <code><a href= + "http://www.python.org/doc/current/lib/bltin-null-object.html">None</a></code>. + Otherwise, the Python argument is created by the same means used for + the return value of a wrapped C++ function returning <code>T</code>. + When <code>T</code> is a class type, that normally means + <code>*x</code> is copy-constructed into the new Python object.</td> + </tr> + + <tr> + <td><code><a href= + "../../../bind/ref.html">boost::reference_wrapper</a><T></code></td> + + <td>The Python argument contains a pointer to, rather than a copy of, + <code>x.get()</code>. Note: failure to ensure that no Python code + holds a reference to the resulting object beyond the lifetime of + <code>*x.get()</code> <b>may result in a crash!</b></td> + </tr> + + <tr> + <td><code><a href= + "ptr.html#pointer_wrapper-spec">pointer_wrapper</a><T></code></td> + + <td>If <code>x.get() == 0</code>, the Python argument will + be <code><a href= + "http://www.python.org/doc/current/lib/bltin-null-object.html">None</a></code>. + Otherwise, the Python argument contains a pointer to, rather than a + copy of, <code>*x.get()</code>. Note: failure to ensure that no + Python code holds a reference to the resulting object beyond the + lifetime of <code>*x.get()</code> <b>may result in a crash!</b></td> + </tr> + </table> + + <h2><a name="result_handling">Result Handling</a></h2> + In general, <code>call<ResultType>()</code> and + <code>call_method<ResultType>()</code> return + <code>ResultType</code> by exploiting all lvalue and rvalue + <code>from_python</code> converters registered for ResultType and + returning a copy of the result. However, when <code>ResultType</code> is + a pointer or reference type, Boost.Python searches only for lvalue + converters. To prevent dangling pointers and references, an exception + will be thrown if the Python result object has only a single reference + count. + + <h2><a name="rationale">Rationale</a></h2> + In general, to get Python arguments corresponding to + <code>a1</code>...<code>a<i>N</i></code>, a new Python object must be + created for each one; should the C++ object be copied into that Python + object, or should the Python object simply hold a reference/pointer to + the C++ object? In general, the latter approach is unsafe, since the + called function may store a reference to the Python object somewhere. If + the Python object is used after the C++ object is destroyed, we'll crash + Python. + + <p>In keeping with the philosophy that users on the Python side shouldn't + have to worry about crashing the interpreter, the default behavior is to + copy the C++ object, and to allow a non-copying behavior only if the user + writes <code><a href="../../../bind/ref.html">boost::ref</a>(a1)</code> + instead of a1 directly. At least this way, the user doesn't get dangerous + behavior "by accident". It's also worth noting that the non-copying + ("by-reference") behavior is in general only available for class types, + and will fail at runtime with a Python exception if used otherwise[<a + href="#1">1</a>].</p> + + <p>However, pointer types present a problem: one approach is to refuse to + compile if any aN has pointer type: after all, a user can always pass + <code>*aN</code> to pass "by-value" or <code>ref(*aN)</code> to indicate + a pass-by-reference behavior. However, this creates a problem for the + expected null pointer to <code>None</code> conversion: it's illegal to + dereference a null pointer value.</p> + + <p>The compromise I've settled on is this:</p> + + <ol> + <li>The default behavior is pass-by-value. If you pass a non-null + pointer, the pointee is copied into a new Python object; otherwise the + corresponding Python argument will be None.</li> + + <li>if you want by-reference behavior, use <code>ptr(aN)</code> if + <code>aN</code> is a pointer and <code>ref(aN)</code> otherwise. If a + null pointer is passed to <code>ptr(aN)</code>, the corresponding + Python argument will be <code>None</code>.</li> + </ol> + + <p>As for results, we have a similar problem: if <code>ResultType</code> + is allowed to be a pointer or reference type, the lifetime of the object + it refers to is probably being managed by a Python object. When that + Python object is destroyed, our pointer dangles. The problem is + particularly bad when the <code>ResultType</code> is char const* - the + corresponding Python String object is typically uniquely-referenced, + meaning that the pointer dangles as soon as <code>call<char + const*>(...)</code> returns.</p> + + <p>The old Boost.Python v1 deals with this issue by refusing to compile + any uses of <code>call<char const*>()</code>, but this goes both + too far and not far enough. It goes too far because there are cases where + the owning Python string object survives beyond the call (just for + instance, when it's the name of a Python class), and it goes not far + enough because we might just as well have the same problem with a + returned pointer or reference of any other type.</p> + + <p>In Boost.Python v2 this is dealt with by:</p> + + <ol> + <li>lifting the compile-time restriction on const char* callback + returns</li> + + <li>detecting the case when the reference count on the result Python + object is 1 and throwing an exception inside of + <code>call<U>(...)</code> when <code>U</code> is a pointer or + reference type.</li> + </ol> + This should be acceptably safe because users have to explicitly specify a + pointer/reference for <code>U</code> in <code>call<U></code>, and + they will be protected against dangles at runtime, at least long enough + to get out of the <code>call<U>(...)</code> invocation. + <hr> + <a name="1">[1]</a> It would be possible to make it fail at compile-time + for non-class types such as int and char, but I'm not sure it's a good + idea to impose this restriction yet. + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + |