how_can_i_find_the_existing_pyob.html 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
  4. <title>How can I find the existing PyObject that holds a C++ object?</title>
  5. <link rel="stylesheet" href="../boostbook.css" type="text/css">
  6. <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
  7. <link rel="home" href="../index.html" title="Boost.Python">
  8. <link rel="up" href="../faq.html" title="Chapter&#160;5.&#160;Frequently Asked Questions (FAQs)">
  9. <link rel="prev" href="does_boost_python_work_with_mac_.html" title="Does Boost.Python work with Mac OS X?">
  10. <link rel="next" href="how_can_i_wrap_a_function_which0.html" title="How can I wrap a function which needs to take ownership of a raw pointer?">
  11. </head>
  12. <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
  13. <table cellpadding="2" width="100%"><tr><td valign="top"><img alt="" width="" height="" src="../images/boost.png"></td></tr></table>
  14. <hr>
  15. <div class="spirit-nav">
  16. <a accesskey="p" href="does_boost_python_work_with_mac_.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../faq.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="how_can_i_wrap_a_function_which0.html"><img src="../images/next.png" alt="Next"></a>
  17. </div>
  18. <div class="section">
  19. <div class="titlepage"><div><div><h3 class="title">
  20. <a name="faq.how_can_i_find_the_existing_pyob"></a><a class="link" href="how_can_i_find_the_existing_pyob.html" title="How can I find the existing PyObject that holds a C++ object?">How can I find
  21. the existing PyObject that holds a C++ object?</a>
  22. </h3></div></div></div>
  23. <div class="blockquote"><blockquote class="blockquote"><p>
  24. "I am wrapping a function that always returns a pointer to an already-held
  25. C++ object."
  26. </p></blockquote></div>
  27. <p>
  28. One way to do that is to hijack the mechanisms used for wrapping a class
  29. with virtual functions. If you make a wrapper class with an initial PyObject*
  30. constructor argument and store that PyObject* as "self", you can
  31. get back to it by casting down to that wrapper type in a thin wrapper function.
  32. For example:
  33. </p>
  34. <pre class="programlisting"><span class="keyword">class</span> <span class="identifier">X</span> <span class="special">{</span> <span class="identifier">X</span><span class="special">(</span><span class="keyword">int</span><span class="special">);</span> <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">X</span><span class="special">();</span> <span class="special">...</span> <span class="special">};</span>
  35. <span class="identifier">X</span><span class="special">*</span> <span class="identifier">f</span><span class="special">();</span> <span class="comment">// known to return Xs that are managed by Python objects</span>
  36. <span class="comment">// wrapping code</span>
  37. <span class="keyword">struct</span> <span class="identifier">X_wrap</span> <span class="special">:</span> <span class="identifier">X</span>
  38. <span class="special">{</span>
  39. <span class="identifier">X_wrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span> <span class="identifier">self</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">self</span><span class="special">(</span><span class="identifier">self</span><span class="special">),</span> <span class="identifier">X</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span> <span class="special">{}</span>
  40. <span class="identifier">PyObject</span><span class="special">*</span> <span class="identifier">self</span><span class="special">;</span>
  41. <span class="special">};</span>
  42. <span class="identifier">handle</span><span class="special">&lt;&gt;</span> <span class="identifier">f_wrap</span><span class="special">()</span>
  43. <span class="special">{</span>
  44. <span class="identifier">X_wrap</span><span class="special">*</span> <span class="identifier">xw</span> <span class="special">=</span> <span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="identifier">X_wrap</span><span class="special">*&gt;(</span><span class="identifier">f</span><span class="special">());</span>
  45. <span class="identifier">assert</span><span class="special">(</span><span class="identifier">xw</span> <span class="special">!=</span> <span class="number">0</span><span class="special">);</span>
  46. <span class="keyword">return</span> <span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">xw</span><span class="special">-&gt;</span><span class="identifier">self</span><span class="special">));</span>
  47. <span class="special">}</span>
  48. <span class="special">...</span>
  49. <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f_wrap</span><span class="special">());</span>
  50. <span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">,</span><span class="identifier">X_wrap</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span>
  51. <span class="special">...</span>
  52. <span class="special">;</span>
  53. </pre>
  54. <p>
  55. Of course, if X has no virtual functions you'll have to use <code class="computeroutput"><span class="keyword">static_cast</span></code> instead of <code class="computeroutput"><span class="keyword">dynamic_cast</span></code>
  56. with no runtime check that it's valid. This approach also only works if the
  57. <code class="computeroutput"><span class="identifier">X</span></code> object was constructed
  58. from Python, because <code class="computeroutput"><span class="identifier">X</span></code>s constructed
  59. from C++ are of course never <code class="computeroutput"><span class="identifier">X_wrap</span></code>
  60. objects.
  61. </p>
  62. <p>
  63. Another approach to this requires you to change your C++ code a bit; if that's
  64. an option for you it might be a better way to go. work we've been meaning
  65. to get to anyway. When a <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;</span></code>
  66. is converted from Python, the shared_ptr actually manages a reference to
  67. the containing Python object. When a shared_ptr&lt;X&gt; is converted back
  68. to Python, the library checks to see if it's one of those "Python object
  69. managers" and if so just returns the original Python object. So you
  70. could just write <code class="computeroutput"><span class="identifier">object</span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> to get
  71. the Python object back. To exploit this you'd have to be able to change the
  72. C++ code you're wrapping so that it deals with shared_ptr instead of raw
  73. pointers.
  74. </p>
  75. <p>
  76. There are other approaches too. The functions that receive the Python object
  77. that you eventually want to return could be wrapped with a thin wrapper that
  78. records the correspondence between the object address and its containing
  79. Python object, and you could have your f_wrap function look in that mapping
  80. to get the Python object out.
  81. </p>
  82. </div>
  83. <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
  84. <td align="left"></td>
  85. <td align="right"><div class="copyright-footer">Copyright &#169; 2002-2015 David
  86. Abrahams, Stefan Seefeld<p>
  87. Distributed under the Boost Software License, Version 1.0. (See accompanying
  88. file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
  89. </p>
  90. </div></td>
  91. </tr></table>
  92. <hr>
  93. <div class="spirit-nav">
  94. <a accesskey="p" href="does_boost_python_work_with_mac_.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../faq.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="how_can_i_wrap_a_function_which0.html"><img src="../images/next.png" alt="Next"></a>
  95. </div>
  96. </body>
  97. </html>