mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 05:42:30 +00:00
129 lines
11 KiB
HTML
129 lines
11 KiB
HTML
<html>
|
|
<head>
|
|
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
<title>Embedding basics</title>
|
|
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
<link rel="prev" href="embedding.html">
|
|
<link rel="next" href="embedding_with_boost_python.html">
|
|
</head>
|
|
<body>
|
|
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
|
<tr>
|
|
<td width="10">
|
|
</td>
|
|
<td width="85%">
|
|
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Embedding basics</b></font>
|
|
</td>
|
|
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="embedding_with_boost_python.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<a name="manual_reference_counting"></a><h2>Manual reference counting</h2><p>
|
|
Most things in Python are objects. Therefore it is only natural that many of the Python C API functions operate on Python objects. Because C/C++ can't work with Python objects directly, the API defines a PyObject structure and a lot of functions to operate on PyObject pointers. </p>
|
|
<p>
|
|
An important property of Python objects, and therefore of PyObjects, is that they are reference counted. This has major advantages compared to 'dumb' copying: it requiring less memory and it avoids unnecessary copying overhead. However, there is a downside as well. Although the reference counting is transparent from the Python-side, it is quite explicit in the C API. In other words you must increase and decrease the reference counts of PyObjects <b>manually</b> using the <a href="http://www.python.org/doc/current/api/countingRefs.html#l2h-65">
|
|
Py_XINCREF</a> and <a href="http://www.python.org/doc/current/api/countingRefs.html#l2h-67">
|
|
Py_XDECREF</a> macros. This is cumbersome, and if you don't do it properly some objects might be released when you still need them, or not be released at all. </p>
|
|
<p>
|
|
I will briefly explain how to update the reference counts correctly, but I'll soon show a better way to do things.</p>
|
|
<p>
|
|
The API functions that return PyObject pointers are listed in the Python C API documentation as either returning a <i>borrowed</i> or a <i>new</i> reference. The difference is in <i>reference ownership</i>. </p>
|
|
<p>
|
|
When a <i>new</i> reference is returned, you own that reference. Therefore you don't need to worry about the object being deallocated while you still need it. You do need to decrease the reference count when you are done with it however, otherwise the object will never be deallocated: you'll have a <i>resource leak</i>. </p>
|
|
<p>
|
|
Here's a simple example:</p>
|
|
<code><pre>
|
|
<span class=comment>// Create a new tuple of 3 elements long
|
|
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>my_tuple </span><span class=special>= </span><span class=identifier>PyTuple_New</span><span class=special>(</span><span class=number>3</span><span class=special>);
|
|
</span><span class=special>... </span><span class=comment>// Use my_tuple here
|
|
// We're done with the tuple
|
|
</span><span class=identifier>Py_XDECREF</span><span class=special>(</span><span class=identifier>my_tuple</span><span class=special>);
|
|
</span></pre></code>
|
|
<p>
|
|
When a <i>borrowed</i> reference is returned, you do not have ownership of the reference. So if you just want to discard the return value, there is nothing you have to do: you didn't own it anyway. If want to use it however, you'll first have to increase its reference count (to prevent the object's deletion). Then later on when you are done with itm you'll need to decrease the reference count again. Here's another example:</p>
|
|
<code><pre>
|
|
<span class=comment>// Retrieve the first item in the tuple
|
|
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>first </span><span class=special>= </span><span class=identifier>PyTuple_GetItem</span><span class=special>(</span><span class=identifier>my_tuple</span><span class=special>, </span><span class=number>0</span><span class=special>);
|
|
</span><span class=identifier>Py_XINCREF</span><span class=special>(</span><span class=identifier>first</span><span class=special>);
|
|
</span><span class=special>... </span><span class=comment>// Use first here
|
|
// We're done with the first tuple item
|
|
</span><span class=identifier>Py_XDECREF</span><span class=special>(</span><span class=identifier>first</span><span class=special>);
|
|
</span></pre></code>
|
|
<p>
|
|
While this certainly works, it's hardly elegant and it's easy to make mistakes, especially when there are multiple execution paths.</p>
|
|
<a name="running_python_code_from_c__"></a><h2>Running Python code from C++</h2><p>
|
|
To run Python code from C++ there is a family of functions in the API starting with the PyRun_ prefix. You can find the list of these fuctions <a href="http://www.python.org/doc/current/api/veryhigh.html">
|
|
here</a>. I shall discuss one of them, the others work very similarly.</p>
|
|
<code><pre>
|
|
<span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=keyword>char </span><span class=special>*</span><span class=identifier>str</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>start</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>globals</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>locals</span><span class=special>)
|
|
</span></pre></code>
|
|
<p>
|
|
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
PyRun_String</a> takes the code to execute as a null-terminated (C-style) string in its <tt>str</tt> parameter. The function returns a new reference to the Python object which results from executing the code. If a Python exception occurred during execution, the null pointer is returned.</p>
|
|
<p>
|
|
The <tt>start</tt> parameter is the start symbol from the Python grammar to use for interpreting the code. The possible values are:</p>
|
|
<table width="90%" border="0" align="center"> <tr>
|
|
<td class="table_title" colspan="6">
|
|
Start symbols </td>
|
|
</tr>
|
|
<tr><tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
Py_eval_input</a></td><td class="table_cells">for interpreting isolated expressions</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
Py_file_input</a></td><td class="table_cells">for interpreting sequences of statements</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60">
|
|
Py_single_input</a></td><td class="table_cells">for interpreting a single statement</td></tr></table>
|
|
<p>
|
|
Lastly, the <tt>globals</tt> and <tt>locals</tt> parameters are Python dictionaries containing the globals and locals of the context in which to run the code. For most intents and purposes you can use the namespace dictionary of the running module for both <tt>globals</tt> and <tt>locals</tt>.</p>
|
|
<p>
|
|
So how do we get a module's namespace dictionary? First we need to get a reference to the module. The function to do this is <a href="http://www.python.org/doc/current/api/importing.html#l2h-125">
|
|
PyImport_AddModule</a>. Contrary to what you might guess from its name, it returns a borrowed reference to an <b>existing</b> module. </p>
|
|
<p>
|
|
Then once we have a reference to the module, we can use <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594">
|
|
PyModule_GetDict</a> to get a borrowed reference to the module's namespace dictionary.</p>
|
|
<p>
|
|
Since the running module is usually the <tt>__main__</tt> module created upon interpreter initialization, the code to execute a Python program from a string becomes:</p>
|
|
<code><pre>
|
|
<span class=comment>// Get the __main__ module namespace
|
|
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>main_module </span><span class=special>= </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>);
|
|
</span><span class=identifier>Py_XINCREF</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>);
|
|
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>main_namespace </span><span class=special>= </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>);
|
|
</span><span class=identifier>Py_XINCREF</span><span class=special>(</span><span class=identifier>main_namespace</span><span class=special>);
|
|
</span><span class=comment>// Run a single Python expression and retrieve the result
|
|
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>result </span><span class=special>= </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"1 + 1"</span><span class=special>,
|
|
</span><span class=identifier>Py_eval_input</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>);
|
|
</span><span class=special>... </span><span class=comment>// Use the result
|
|
// Cleanup
|
|
</span><span class=identifier>Py_XDECREF</span><span class=special>(</span><span class=identifier>result</span><span class=special>);
|
|
</span><span class=identifier>Py_XDECREF</span><span class=special>(</span><span class=identifier>main_namespace</span><span class=special>);
|
|
</span><span class=identifier>Py_XDECREF</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>);
|
|
</span></pre></code>
|
|
<table width="80%" border="0" align="center">
|
|
<tr>
|
|
<td class="note_box">
|
|
<img src="theme/alert.gif"></img> <b>Warning</b><br><br>
|
|
|
|
Be careful about what Python code you run and where. Running the addition above on your computer can hardly do any harm. But letting users run arbitrary Python code through your program which is running on a webserver can be a security risk.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<blockquote><p><i><b>Next up: How Boost.Python can simplify embedding...</b></i></p></blockquote><table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="embedding_with_boost_python.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<hr size="1"><p class="copyright">Copyright © 2002 Dirk Gerrits <br><br>
|
|
<font size="2">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. </font> </p>
|
|
</body>
|
|
</html>
|