Improve Python docs on memory management and member variables
This commit is contained in:
parent
c2e811c12d
commit
2315ed878b
2 changed files with 64 additions and 26 deletions
|
|
@ -1671,6 +1671,7 @@
|
||||||
<li><a href="Python.html#Python_nn62">Mapping Python tuples into small arrays</a>
|
<li><a href="Python.html#Python_nn62">Mapping Python tuples into small arrays</a>
|
||||||
<li><a href="Python.html#Python_nn63">Mapping sequences to C arrays</a>
|
<li><a href="Python.html#Python_nn63">Mapping sequences to C arrays</a>
|
||||||
<li><a href="Python.html#Python_nn64">Pointer handling</a>
|
<li><a href="Python.html#Python_nn64">Pointer handling</a>
|
||||||
|
<li><a href="Python.html#Python_memory_management_member_variables">Memory management when returning references to member variables</a>
|
||||||
</ul>
|
</ul>
|
||||||
<li><a href="Python.html#Python_nn65">Docstring Features</a>
|
<li><a href="Python.html#Python_nn65">Docstring Features</a>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
||||||
|
|
@ -5435,7 +5435,7 @@ that has a <tt>this</tt> attribute. In addition,
|
||||||
class object (if applicable).
|
class object (if applicable).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<H3><a name="Python_memory_management_member_variables">36.9.7 Memory management when returning references to member variables</a></H3>
|
<H3><a name="Python_memory_management_member_variables">38.9.7 Memory management when returning references to member variables</a></H3>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -5449,9 +5449,11 @@ Consider the following C++ code:
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
|
#include <iostream>
|
||||||
struct Wheel {
|
struct Wheel {
|
||||||
int size;
|
int size;
|
||||||
Wheel(int sz) : size(sz) {}
|
Wheel(int sz) : size(sz) {}
|
||||||
|
~Wheel() { std::cout << "~Wheel" << std::endl; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bike {
|
class Bike {
|
||||||
|
|
@ -5474,7 +5476,7 @@ bike = Bike(10)
|
||||||
wheel = bike.getWheel()
|
wheel = bike.getWheel()
|
||||||
print("wheel size: {}".format(wheel.size))
|
print("wheel size: {}".format(wheel.size))
|
||||||
|
|
||||||
del bike # Allow bike to be garbage collected
|
del bike # Allow bike to be garbage collected
|
||||||
print("wheel size: {}".format(wheel.size))
|
print("wheel size: {}".format(wheel.size))
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -5486,6 +5488,7 @@ Don't be surprised that if the resulting output gives strange results such as...
|
||||||
<div class="shell">
|
<div class="shell">
|
||||||
<pre>
|
<pre>
|
||||||
wheel size: 10
|
wheel size: 10
|
||||||
|
~Wheel
|
||||||
wheel size: 135019664
|
wheel size: 135019664
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -5499,66 +5502,100 @@ be added to the <tt>wheel</tt> instance.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You can do this by adding the reference when the <tt>getWheel()</tt> method
|
You can do this by adding the reference when the <tt>getWheel()</tt> method
|
||||||
is called using one of two approaches:
|
is called using one of three approaches:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The easier, but less optimized, way is to use the typemap-like <tt>%pythonappend</tt> directive
|
The easier, but less optimized, way is to use the <tt>%pythonappend</tt> directive
|
||||||
(see <a href="#Python_nn42">36.6.2 Adding additional Python code</a>):
|
(see <a href="#Python_nn42">Adding additional Python code</a>):
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
%pythonappend getWheel %{
|
%pythonappend getWheel %{
|
||||||
# val is the Wheel proxy, self is the Bike instance
|
# val is the Wheel proxy, self is the Bike instance
|
||||||
val._bike = self
|
val.__bike_reference = self
|
||||||
%}
|
%}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The code gets appended to the Python code generated for the
|
The code gets appended to the Python code generated for the
|
||||||
<tt>Bike::getWheel</tt> function, where we store the <tt>Bike</tt> proxy
|
<tt>Bike::getWheel</tt> wrapper function, where we store the <tt>Bike</tt> proxy
|
||||||
instance onto the <tt>Wheel</tt> proxy instance before it is returned to the
|
instance onto the <tt>Wheel</tt> proxy instance before it is returned to the
|
||||||
caller.
|
caller as follows.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="targetlang">
|
||||||
|
<pre>
|
||||||
|
class Bike(object):
|
||||||
|
...
|
||||||
|
def getWheel(self):
|
||||||
|
val = _example.Bike_getWheel(self)
|
||||||
|
|
||||||
|
# val is the Wheel proxy, self is the Bike instance
|
||||||
|
val.__bike_reference = self
|
||||||
|
|
||||||
|
return val
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The second option, which performs better and is required if you use the
|
The second option, which performs better and is required if you use the
|
||||||
<tt>-builtin</tt> option, is to set the reference in the CPython implementation:
|
<tt>-builtin</tt> option, is to set the reference in the CPython implementation:
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
%fragment("extra_reference", "header") {
|
%extend Wheel {
|
||||||
|
// A reference to the parent class is added to ensure the underlying C++
|
||||||
|
// object is not deleted while the item is in use
|
||||||
|
%typemap(ret) Wheel& getWheel {
|
||||||
|
PyObject *bike_reference_string = SWIG_Python_str_FromChar("__bike_reference");
|
||||||
|
PyObject_SetAttr($result, bike_reference_string, $self);
|
||||||
|
Py_DecRef(bike_reference_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
static PyObject *extra_reference() {
|
<p>
|
||||||
static PyObject *extra_reference_string = NULL;
|
The third approach, shown below, is an optimization of the above approach and creates the "__bike_reference" Python string object just once.
|
||||||
if (!extra_reference_string)
|
While this looks more complex, it is just a small variation on the above typemap plus a support function
|
||||||
extra_reference_string = SWIG_Python_str_FromChar("_extra_reference");
|
<tt>bike_reference()</tt> in a fragment called <tt>bike_reference_function</tt>.
|
||||||
return extra_reference_string;
|
The <tt>bike_reference_init</tt> typemap generates code into the "init" section for an initial call to <tt>bike_reference()</tt> when the module
|
||||||
|
is initialized and is done to create the "__bike_reference" Python string singleton in a thread-safe manner.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("bike_reference_init", "init") {
|
||||||
|
// Thread-safe initialization - initialize during Python module initialization
|
||||||
|
bike_reference();
|
||||||
|
}
|
||||||
|
|
||||||
|
%fragment("bike_reference_function", "header", fragment="bike_reference_init") {
|
||||||
|
|
||||||
|
static PyObject *bike_reference() {
|
||||||
|
static PyObject *bike_reference_string = SWIG_Python_str_FromChar("__bike_reference");
|
||||||
|
return bike_reference_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
%extend Wheel {
|
%extend Wheel {
|
||||||
%typemap(ret, fragment="extra_reference") Wheel& getWheel %{
|
// A reference to the parent class is added to ensure the underlying C++
|
||||||
// A reference to the parent class is added to ensure the underlying C++
|
// object is not deleted while the item is in use
|
||||||
// object is not deleted while the item is in use
|
%typemap(ret, fragment="bike_reference_function") Wheel& getWheel %{
|
||||||
PyObject_SetAttr($result, extra_reference(), $self);
|
PyObject_SetAttr($result, bike_reference(), $self);
|
||||||
%}
|
%}
|
||||||
/* FYI: Alternative approach, but is possibly harder to understand, so suggest above
|
|
||||||
%typemap(out, fragment="extra_reference") Wheel& getWheel %{
|
|
||||||
$typemap(out, Wheel &)
|
|
||||||
// A reference to the parent class is added to ensure the underlying C++
|
|
||||||
// object is not deleted while the item is in use
|
|
||||||
PyObject_SetAttr($result, extra_reference(), $self);
|
|
||||||
%}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<H2><a name="Python_nn65">38.10 Docstring Features</a></H2>
|
<H2><a name="Python_nn65">38.10 Docstring Features</a></H2>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue