mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
247 lines
9.2 KiB
HTML
247 lines
9.2 KiB
HTML
<html>
|
|
<head>
|
|
<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="../../../../c++boost.gif" border="0"></a></h3>
|
|
</td>
|
|
<td valign="top">
|
|
<h1 align="center">Boost.Python</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>
|
|
<p>
|
|
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. The interface for
|
|
calling a Python function object (or any Python callable object) looks
|
|
like:
|
|
|
|
<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>
|
|
|
|
|
|
<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#reference_wrapper">ref()</a>:
|
|
|
|
<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>Behavior
|
|
|
|
<tr>
|
|
<td><code>T cv&</code><br>
|
|
<code>T cv</code>
|
|
|
|
<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.
|
|
|
|
<tr>
|
|
<td><code>T*</code>
|
|
|
|
<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.
|
|
|
|
<tr>
|
|
<td><code><a
|
|
href="../../../bind/ref.html#reference_wrapper">boost::reference_wrapper</a><T> </code>
|
|
|
|
<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>
|
|
|
|
<tr>
|
|
<td><code><a
|
|
href="ptr.html#pointer_wrapper-spec">pointer_wrapper</a><T></code>
|
|
|
|
<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>
|
|
|
|
</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>
|
|
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>
|
|
|
|
The compromise I've settled on is this:
|
|
|
|
<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>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>.
|
|
</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>
|
|
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>
|
|
|
|
In Boost.Python v2 this is dealt with by:
|
|
|
|
<ol>
|
|
<li> lifting the compile-time restriction on const
|
|
char* callback returns
|
|
|
|
|
|
<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.
|
|
</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 -->
|
|
17 April, 2002
|
|
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
</p>
|
|
<p><i>© Copyright <a href="../../../../people/dave_abrahams.htm">Dave Abrahams</a>
|
|
2002. All Rights Reserved.</i></p>
|
|
</body>
|
|
</html>
|