diff --git a/doc/tutorial/doc/html/index.html b/doc/tutorial/doc/html/index.html index ffe9a7c1..6562206f 100644 --- a/doc/tutorial/doc/html/index.html +++ b/doc/tutorial/doc/html/index.html @@ -1,14 +1,11 @@ - - -
Last revised: August 31, 2006 at 05:59:58 GMT |
+Last revised: May 18, 2007 at 15:45:45 GMT |
-- To be able to use embedding in your programs, they have to be linked to both - Boost.Python's and Python's static link library. + To be able to embed python into your programs, you have to link to both Boost.Python's + as well as Python's own runtime library.
- Boost.Python's static link library comes in two variants. Both are located
- in Boost's /libs/python/build/bin-stage subdirectory. On
- Windows, the variants are called boost_python.lib (for release
- builds) and boost_python_debug.lib (for debugging). If you
- can't find the libraries, you probably haven't built Boost.Python yet. See
- Building and Testing on how to
- do this.
+ Boost.Python's library comes in two variants. Both are located in Boost's
+ /libs/python/build/bin-stage subdirectory. On Windows, the
+ variants are called boost_python.lib (for release builds)
+ and boost_python_debug.lib (for debugging). If you can't
+ find the libraries, you probably haven't built Boost.Python yet. See Building and Testing on how to do this.
- Python's static link library can be found in the /libs subdirectory
+ Python's library can be found in the /libs subdirectory
of your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.
- Additionally, Python's /include subdirectory has to be added
+ Additionally, Python's /include subdirectory has to be added
to your include path.
@@ -86,44 +81,49 @@ exe embedded_program # name of the executable <library-path>$(PYTHON_LIB_PATH) <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; -
Being able to build is nice, but there is nothing to build yet. Embedding the Python interpreter into one of your C++ programs requires these 4 steps:
<boost/python.hpp>_main_
module. Note that at this time
+ you must not call Py_Finalize()
+ to stop the interpreter. This may be fixed in a future version of boost.python.
+ |
(Of course, there can be other C++ code between all of these steps.)
- Now that we can embed the interpreter in - our programs, lets see how to put it to use... + Now that we can embed the interpreter in + our programs, lets see how to put it to use...
As you probably already know, objects in Python are reference-counted. Naturally,
- the PyObjects of the Python/C API are also reference-counted.
+ the PyObjects of the Python/C API are also reference-counted.
There is a difference however. While the reference-counting is fully automatic
in Python, the Python/C API requires you to do it by
hand. This is messy and especially hard to get right in the presence
@@ -131,240 +131,106 @@ exe embedded_program # name of the executable
and object class templates to
automate the process.
- There are two ways in which a function in the Python/C API can return a - PyObject*: as a borrowed reference - or as a new reference. Which of these a function uses, - is listed in that function's documentation. The two require slightely different - approaches to reference-counting but both can be 'handled' by Boost.Python. -
-- For a function returning a borrowed reference we'll - have to tell the handle that the PyObject* - is borrowed with the aptly named borrowed - function. Two functions returning borrowed references are PyImport_AddModule - and PyModule_GetDict. - The former returns a reference to an already imported module, the latter - retrieves a module's namespace dictionary. Let's use them to retrieve the - namespace of the _main_ - module: -
--object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - -object main_namespace = main_module.attr("__dict__"); --
- For a function returning a new reference we can just - create a handle out of the raw PyObject* - without wrapping it in a call to borrowed. One such function that returns - a new reference is PyRun_String - which we'll discuss in the next section. -
-
-
Handle is a class template,
- so why haven't we been using any template parameters?
- handle has a single template parameter specifying the
- type of the managed object. This type is PyObject 99%
- of the time, so the parameter was defaulted to PyObject
- for convenience. Therefore we can use the shorthand handle<>
- instead of the longer, but equivalent, handle<PyObject>.
-
- To run Python code from C++ there is a family of functions in the API starting - with the PyRun prefix. You can find the full list of these functions here. They - all work similarly so we will look at only one of them, namely: + Boost.python provides three related functions to run Python code from C++.
-PyObject* PyRun_String(char *str, int start, PyObject *globals, PyObject *locals) +object eval(str expression, object globals = object(), object locals = object()) +object exec(str code, object globals = object(), object locals = object()) +object exec_file(str filename, object globals = object(), object locals = object())
- PyRun_String - takes the code to execute as a null-terminated (C-style) string in its str - parameter. The function returns a new reference to a Python object. Which - object is returned depends on the start paramater. + eval evaluates the given expression and returns the resulting value. exec + executes the given code (typically a set of statements) returning the result, + and exec_file executes the code contained in the given file.
- The start parameter is the start symbol from the Python - grammar to use for interpreting the code. The possible values are: -
-| Py_eval_input | -for - interpreting isolated expressions | -
|---|---|
| Py_file_input | -for - interpreting sequences of statements | -
| Py_single_input | -for - interpreting a single statement | -
- When using Py_eval_input, - the input string must contain a single expression and its result is returned. - When using Py_file_input, - the string can contain an abitrary number of statements and None is returned. - Py_single_input - works in the same way as Py_file_input - but only accepts a single statement. -
-
- Lastly, the globals and locals 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 _main_
+ The globals and locals 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 _main_
module for both parameters.
- We have already seen how to get the _main_ - module's namespace so let's run some Python code in it: + Boost.python provides a function to import a module:
-object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - -object main_namespace = main_module.attr("__dict__"); - -handle<> ignored((PyRun_String( - - "hello = file('hello.txt', 'w')\n" - "hello.write('Hello world!')\n" - "hello.close()" - - , Py_file_input - , main_namespace.ptr() - , main_namespace.ptr()) -)); +object import(str name)
- Because the Python/C API doesn't know anything about objects, - we used the object's ptr member function to retrieve the - PyObject*. + import imports a python module (potentially loading it into the running process + first), and returns it.
+
+ Let's import the _main_
+ module and run some Python code in its namespace:
+
+object main_module = import("__main__"); +object main_namespace = main_module.attr("__dict__"); + +object ignored = exec("hello = file('hello.txt', 'w')\n" + "hello.write('Hello world!')\n" + "hello.close()", + main_namespace); +
This should create a file called 'hello.txt' in the current directory containing a phrase that is well-known in programming circles.
-
-
Note that we wrap
- the return value of PyRun_String
- in a (nameless) handle even though we are not interested
- in it. If we didn't do this, the the returned object would be kept alive
- unnecessarily. Unless you want to be a Dr. Frankenstein, always wrap PyObject*s
- in handles.
-
- It's nice that handle manages the reference counting details
- for us, but other than that it doesn't do much. Often we'd like to have a
- more useful class to manipulate Python objects. But we have already seen
- such a class above, and in the previous section:
- the aptly named object class and it's derivatives. We've
- already seen that they can be constructed from a handle.
+ Often we'd like to have a class to manipulate Python objects. But we have
+ already seen such a class above, and in the previous
+ section: the aptly named object class and its
+ derivatives. We've already seen that they can be constructed from a handle.
The following examples should further illustrate this fact:
-object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - +object main_module = import("__main__"); object main_namespace = main_module.attr("__dict__"); - -handle<> ignored((PyRun_String( - - "result = 5 ** 2" - - , Py_file_input - , main_namespace.ptr() - , main_namespace.ptr()) -)); - +object ignored = exec("result = 5 ** 2", main_namespace); int five_squared = extract<int>(main_namespace["result"]);
- Here we create a dictionary object for the _main_
+ Here we create a dictionary object for the _main_
module's namespace. Then we assign 5 squared to the result variable and read
this variable from the dictionary. Another way to achieve the same result
- is to let PyRun_String
- return the result directly with Py_eval_input:
+ is to use eval instead, which returns the result directly:
-object result((handle<>( - PyRun_String("5 ** 2" - , Py_eval_input - , main_namespace.ptr() - , main_namespace.ptr())) -)); - +object result = eval("5 ** 2"); int five_squared = extract<int>(result);-
-
Note that object's
- member function to return the wrapped PyObject* is called
- ptr instead of get. This makes sense
- if you take into account the different functions that object
- and handle perform.
-
- If an exception occurs in the execution of some Python code, the PyRun_String - function returns a null pointer. Constructing a handle - out of this null pointer throws error_already_set, - so basically, the Python exception is automatically translated into a C++ - exception when using handle: + If an exception occurs in the evaluation of the python expression, error_already_set + is thrown:
try { - object result((handle<>(PyRun_String( - "5/0" - , Py_eval_input - , main_namespace.ptr() - , main_namespace.ptr())) - )); - + object result = eval("5/0"); // execution will never get here: int five_divided_by_zero = extract<int>(result); } -catch(error_already_set) +catch(error_already_set const &) { // handle the exception in some way }
- The error_already_set exception class doesn't carry any
+ The error_already_set exception class doesn't carry any
information in itself. To find out more about the Python exception that occurred,
you need to use the exception
handling functions of the Python/C API in your catch-statement. This
@@ -374,7 +240,7 @@ exe embedded_program # name of the executable
exceptions:
-catch(error_already_set) +catch(error_already_set const &) { if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) { @@ -391,23 +257,6 @@ exe embedded_program # name of the executable (To retrieve even more information from the exception you can use some of the other exception handling functions listed here.) -- If you'd rather not have handle throw a C++ exception - when it is constructed, you can use the allow_null - function in the same way you'd use borrowed: -
--handle<> result((allow_null(PyRun_String( - "5/0" - , Py_eval_input - , main_namespace.ptr() - , main_namespace.ptr())))); - -if (!result) - // Python exception occurred -else - // everything went okay, it's safe to use the result -
MSVC6/7 Workaround+ If you are using Microsoft Visual C++ 6 or 7, you have to write + f as:+ return call<int>(this->get_override("f").ptr());. |
+ BaseWrap's overridden virtual member function f
+ in effect calls the corresponding method of the Python object through get_override.
- BaseWrap's overridden virtual member function f - in effect calls the corresponding method of the Python object through get_override. -
-
- Finally, exposing Base:
+ Finally, exposing Base:
class_<BaseWrap, boost::noncopyable>("Base") @@ -399,14 +399,18 @@ ;
- pure_virtual signals Boost.Python
- that the function f is a
+ pure_virtual signals Boost.Python
+ that the function f is a
pure virtual function.
-
member function and methods
-
Python, like many object oriented languages uses the term methods. Methods correspond roughly to C++'s member functions
-
member function and
+ methodsPython, like many object oriented languages + uses the term methods. Methods correspond + roughly to C++'s member functions + |
We've seen in the previous section how classes with pure virtual functions are wrapped using Boost.Python's class - wrapper facilities. If we wish to wrap non-pure-virtual + wrapper facilities. If we wish to wrap non-pure-virtual functions instead, the mechanism is a bit different.
@@ -429,8 +433,8 @@ };
- had a pure virtual function f. If, however, its member
- function f was not declared as pure virtual:
+ had a pure virtual function f. If, however, its member
+ function f was not declared as pure virtual:
struct Base @@ -456,15 +460,16 @@ };
- Notice how we implemented BaseWrap::f. Now, - we have to check if there is an override for f. - If none, then we call Base::f(). -
-
-
MSVC6/7 Workaround
-
If you are using Microsoft Visual C++ 6 or 7, you have to rewrite
- the line with the *note* as:
return call<char const*>(f.ptr());.
+ Notice how we implemented BaseWrap::f. Now,
+ we have to check if there is an override for f.
+ If none, then we call Base::f().
MSVC6/7 Workaround+ If you are using Microsoft Visual C++ 6 or 7, you have to rewrite + the line with the *note* as:return call<char const*>(f.ptr());. |
Finally, exposing:
@@ -474,10 +479,10 @@ ;
- Take note that we expose both &Base::f and &BaseWrap::default_f. Boost.Python needs to keep track
- of 1) the dispatch function f and 2) the forwarding function
- to its default implementation default_f. There's a special
- def function for this purpose.
+ Take note that we expose both &Base::f and &BaseWrap::default_f. Boost.Python needs to keep track
+ of 1) the dispatch function f and 2) the forwarding function
+ to its default implementation default_f. There's a special
+ def function for this purpose.
In Python, the results would be as expected: @@ -493,14 +498,14 @@ >>> derived = Derived()
- Calling base.f():
+ Calling base.f():
>>> base.f() 0
- Calling derived.f():
+ Calling derived.f():
>>> derived.f() @@ -510,17 +515,17 @@-- +
++ Python Operators -
C is well known for the abundance of operators. C++ extends this to the extremes by allowing operator overloading. Boost.Python takes advantage of this and makes it easy to wrap C++ operator-powered classes.
- Consider a file position class FilePos and a set of operators + Consider a file position class
FilePosand a set of operators that take on FilePos instances:@@ -553,16 +558,16 @@
The code snippet above is very clear and needs almost no explanation at all. It is virtually the same as the operators' signatures. Just take note that - self refers to FilePos object. Also, not every class - T that you might need to interact with in an operator - expression is (cheaply) default-constructible. You can use other<T>() - in place of an actual T instance when writing "self +
-selfrefers to FilePos object. Also, not every class +Tthat you might need to interact with in an operator + expression is (cheaply) default-constructible. You can useother<T>()+ in place of an actualTinstance when writing "self expressions".- +
++ Special Methods -
Python has a few more Special Methods. Boost.Python supports all of the standard special method names supported by real Python @@ -588,12 +593,11 @@
Need we say more?
--
+What is the business of operator<<? Well, the method str - requires the operator<< - to do its work (i.e. operator<< is used by the method defined by - def(str(self)). -
+
+ + What is the business of
operator<<? Well, the methodstrrequires theoperator<<to do its work (i.e.operator<<+ is used by the method defined bydef(str(self)).
Remember the Zen, Luke:+ "Explicit is better than implicit" "In + the face of ambiguity, refuse the temptation to guess" + |
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
- pointers carry no default argument info. Take a function f
+ pointers carry no default argument info. Take a function f
with default arguments:
int f(int, double = 3.14, char const* = "hello");
- But the type of a pointer to the function f has no information
+ But the type of a pointer to the function f has no information
about its default arguments:
int(*g)(int,double,char const*) = f; // defaults lost!
- When we pass this function pointer to the def function,
+ When we pass this function pointer to the def function,
there is no way to retrieve the default arguments:
@@ -404,10 +403,10 @@ Namespaces are one honking great idea -- let's do more of those!
are overloaded with a common sequence of initial arguments
Boost.Python now has a way to make it easier. For instance, given a function:
@@ -425,19 +424,19 @@ Namespaces are one honking great idea -- let's do more of those!
will automatically create the thin wrappers for us. This macro will create
- a class foo_overloads that can be passed on to def(...).
+ a class foo_overloads that can be passed on to def(...).
The third and fourth macro argument are the minimum arguments and maximum
- arguments, respectively. In our foo function the minimum
- number of arguments is 1 and the maximum number of arguments is 4. The def(...)
+ arguments, respectively. In our foo function the minimum
+ number of arguments is 1 and the maximum number of arguments is 4. The def(...)
function will automatically add all the foo variants for us:
def("foo", foo, foo_overloads());-
Objects here, objects there, objects here there everywhere. More frequently than anything else, we need to expose member functions of our classes to @@ -446,7 +445,7 @@ Namespaces are one honking great idea -- let's do more of those! play. Another macro is provided to make this a breeze.
- Like BOOST_PYTHON_FUNCTION_OVERLOADS, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
+ Like BOOST_PYTHON_FUNCTION_OVERLOADS, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
may be used to automatically create the thin wrappers for wrapping member
functions. Let's have an example:
- will generate a set of thin wrappers for george's wack_em
+ will generate a set of thin wrappers for george's wack_em
member function accepting a minimum of 1 and a maximum of 3 arguments (i.e.
the third and fourth macro argument). The thin wrappers are all enclosed
- in a class named george_overloads that can then be used
- as an argument to def(...):
+ in a class named george_overloads that can then be used
+ as an argument to def(...):
.def("wack_em", &george::wack_em, george_overloads()); @@ -480,13 +479,13 @@ Namespaces are one honking great idea -- let's do more of those! See the overloads reference for details. -- +
++ init and optional -
A similar facility is provided for class constructors, again, with default - arguments or a sequence of overloads. Remember init<...>? + arguments or a sequence of overloads. Remember
init<...>? For example, given a class X with a constructor:@@ -503,7 +502,7 @@ Namespaces are one honking great idea -- let's do more of those! .def(init<int, optional<char, std::string, double> >())- Notice the use of init<...> and optional<...> + Notice the use of
@@ -511,8 +510,8 @@ Namespaces are one honking great idea -- let's do more of those!init<...>andoptional<...>to signify the default (optional arguments).- It was mentioned in passing in the previous section that BOOST_PYTHON_FUNCTION_OVERLOADS - and BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS can also be + It was mentioned in passing in the previous section that
@@ -554,24 +553,24 @@ Namespaces are one honking great idea -- let's do more of those! Notice though that we have a situation now where we have a minimum of zero (0) arguments and a maximum of 3 arguments. -BOOST_PYTHON_FUNCTION_OVERLOADS+ andBOOST_PYTHON_MEMBER_FUNCTION_OVERLOADScan also be used for overloaded functions and member functions with a common sequence of initial arguments. Here is an example:- +
++ Manual Wrapping -
- It is important to emphasize however that the overloaded - functions must have a common sequence of initial arguments. Otherwise, + It is important to emphasize however that the overloaded + functions must have a common sequence of initial arguments. Otherwise, our scheme above will not work. If this is not the case, we have to wrap our functions manually.
Actually, we can mix and match manual wrapping of overloaded functions and - automatic wrapping through BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS - and its sister, BOOST_PYTHON_FUNCTION_OVERLOADS. Following + automatic wrapping through
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS+ and its sister,BOOST_PYTHON_FUNCTION_OVERLOADS. Following up on our example presented in the section on overloading, since the first 4 overload functins have a common sequence - of initial arguments, we can use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS - to automatically wrap the first three of the defs and + of initial arguments, we can useBOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS+ to automatically wrap the first three of thedefs and manually wrap just the last. Here's how we'll do this:diff --git a/doc/tutorial/doc/html/python/hello.html b/doc/tutorial/doc/html/python/hello.html index efdba8c2..1572c90a 100644 --- a/doc/tutorial/doc/html/python/hello.html +++ b/doc/tutorial/doc/html/python/hello.html @@ -1,16 +1,13 @@ - - - -Building Hello World +Building Hello World - + - +
Building without bjam+ Besides bjam, there are of course other ways to get your module + built. What's written here should not be taken as "the one and only + way". There are of course other build tools apart from bjam.+ Take note however that the preferred build tool for Boost.Python + is bjam. There are so many ways to set up the build incorrectly. Experience + shows that 90% of the "I can't build Boost.Python" problems + come from people who had to use a different tool. |
We shall skip over the details. Our objective will be to simply create the hello world module and run it in Python. For a complete reference to building @@ -78,7 +76,7 @@ if you are on Unix.
- The tutorial example can be found in the directory: libs/python/example/tutorial.
+ The tutorial example can be found in the directory: libs/python/example/tutorial.
There, you can find:
- The hello.cpp file is our C++ hello world example. The
- Jamfile is a minimalist bjam script
+ The hello.cpp file is our C++ hello world example. The
+ Jamfile is a minimalist bjam script
that builds the DLLs for us.
Before anything else, you should have the bjam executable in your boost directory
- or somewhere in your path such that bjam can be executed
+ or somewhere in your path such that bjam can be executed
in the command line. Pre-built Boost.Jam executables are available for most
platforms. The complete list of Bjam executables can be found here.
First, we need to specify our location. You may place your project anywhere.
- project-root allows you to do that.
+ project-root allows you to do that.
project-root ;
By doing so, you'll need a Jamrules file. Simply copy the one in the example/tutorial directory
- and tweak the path-global BOOST_ROOT to where your boost
+ and tweak the path-global BOOST_ROOT to where your boost
root directory is. The file has detailed
instructions you can follow.
import python ;
- Finally we declare our hello extension:
+ Finally we declare our hello extension:
extension hello # Declare a Python extension called hello : hello.cpp # source @@ -151,10 +149,10 @@ extension hello # Declare a Python extension called helloThe last part tells BJam that we are depending on the Boost Python Library.
-- +
++ Running bjam -
bjam is run using your operating system's command line interpreter. @@ -164,7 +162,7 @@ extension hello # Declare a Python extension called hello
Make sure that the environment is set so that we can invoke the C++ compiler.
- With MSVC, that would mean running the Vcvars32.bat batch
+ With MSVC, that would mean running the Vcvars32.bat batch
file. For instance:
C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat @@ -177,21 +175,22 @@ extension hello # Declare a Python extension called hello set PYTHON_VERSION=2.2
- The above assumes that the Python installation is in c:/dev/tools/python
+ The above assumes that the Python installation is in c:/dev/tools/python
and that we are using Python version 2.2. You'll have to tweak these appropriately.
-
Be sure not to include a third number, e.g. not "2.2.1", even if that's the version you
- have.
-
Be sure not to include a third number, e.g. not "2.2.1", even if that's the version
+ you have. |
Take note that you may also do that through the Jamrules file we put in our project as detailed above. The file has detailed instructions you can follow.
- Now we are ready... Be sure to cd to libs/python/example/tutorial
- where the tutorial "hello.cpp" and the "Jamfile"
+ Now we are ready... Be sure to cd to libs/python/example/tutorial
+ where the tutorial "hello.cpp" and the "Jamfile"
is situated.
@@ -254,8 +253,8 @@ b and object bin\tutorial\hello.pyd\vc-7_1\debug\threading-multi\hello.exp if you are on Unix.
- boost_python.dll and hello.pyd can be
- found somewhere in your project's bin directory. After a
+ boost_python.dll and hello.pyd can be
+ found somewhere in your project's bin directory. After a
successful build, you make it possible for the system to find boost_python.dll
or libboost_python.so (usually done with LD_LIBRARY_PATH, DYLD_LIBRARY_PATH,
or some other variable on *nix and with PATH on Windows) and for Python to
@@ -274,7 +273,7 @@ b and object bin\tutorial\hello.pyd\vc-7_1\debug\threading-multi\hello.exp
- There you go... Have fun! + There you go... Have fun!
Beware the
+ common pitfall of forgetting that the constructors of most of Python's
+ mutable types make copies, just as in Python. |
Python:
@@ -198,12 +196,12 @@ dict d(x.attr("__dict__")); // copies x.__dict__ d['whatever'] = 3; // modifies the copy -
- Due to the dynamic nature of Boost.Python objects, any class_<T>
+ Due to the dynamic nature of Boost.Python objects, any class_<T>
may also be one of these types! The following code snippet wraps the class
(type) object.
At some point, we will need to get C++ values out of object instances. This
- can be achieved with the extract<T> function. Consider
+ can be achieved with the extract<T> function. Consider
the following:
double x = o.attr("length"); // compile error
- In the code above, we got a compiler error because Boost.Python object
- can't be implicitly converted to doubles. Instead, what
+ In the code above, we got a compiler error because Boost.Python object
+ can't be implicitly converted to doubles. Instead, what
we wanted to do above can be achieved by writing:
@@ -243,14 +241,14 @@
The first line attempts to extract the "length" attribute of the
- Boost.Python object. The second line attempts to extract
- the Vec2 object from held by the Boost.Python object.
+ Boost.Python object. The second line attempts to extract
+ the Vec2 object from held by the Boost.Python object.
Take note that we said "attempt to" above. What if the Boost.Python
- object does not really hold a Vec2
+ object does not really hold a Vec2
type? This is certainly a possibility considering the dynamic nature of Python
- objects. To be on the safe side, if the C++ type can't
+ objects. To be on the safe side, if the C++ type can't
be extracted, an appropriate exception is thrown. To avoid an exception,
we need to test for extractibility:
-
The astute reader might have noticed that the extract<T>
+
The astute reader might have noticed that the extract<T>
facility in fact solves the mutable copying problem:
@@ -273,8 +271,8 @@ EnumsBoost.Python has a nifty facility to capture and wrap C++ enums. While Python - has no enum type, we'll often want to expose our C++ enums - to Python as an int. Boost.Python's enum facility makes + has no
enumtype, we'll often want to expose our C++ enums + to Python as anint. Boost.Python's enum facility makes this easy while taking care of the proper conversions from Python's dynamic typing to C++'s strong static typing (in C++, ints cannot be implicitly converted to enums). To illustrate, given a C++ enum: @@ -293,16 +291,18 @@
can be used to expose to Python. The new enum type is created in the current
- scope(), which is usually the current module. The snippet
- above creates a Python class derived from Python's int
+ scope(), which is usually the current module. The snippet
+ above creates a Python class derived from Python's int
type which is associated with the C++ type passed as its first parameter.
-
what is a scope?
-
The scope is a class that has an associated global Python object which
- controls the Python namespace in which new extension classes and wrapped
- functions will be defined as attributes. Details can be found here.
-
what is a scope?+ The scope is a class that has an associated global Python object + which controls the Python namespace in which new extension classes + and wrapped functions will be defined as attributes. Details can be + found here. |
You can access those values in Python as
diff --git a/doc/tutorial/doc/html/python/techniques.html b/doc/tutorial/doc/html/python/techniques.html index a60b7278..fb5e9573 100644 --- a/doc/tutorial/doc/html/python/techniques.html +++ b/doc/tutorial/doc/html/python/techniques.html @@ -1,15 +1,12 @@ - - - - The extension .pyd is used
+ for python extension modules, which are just shared libraries. Using
+ the default for your system, like .so for Unix and
+ .dll for Windows, works just as well. |
Now, we create this directory structure for our Python package:
@@ -115,12 +113,12 @@ io.pyd
- The file __init__.py is what tells Python that the directory
- sounds/ is actually a Python package. It can be a empty
+ The file __init__.py is what tells Python that the directory
+ sounds/ is actually a Python package. It can be a empty
file, but can also perform some magic, that will be shown later.
- Now our package is ready. All the user has to do is put sounds
+ Now our package is ready. All the user has to do is put sounds
into his PYTHONPATH
and fire up the interpreter:
Note that we added an underscore to the module name. The filename will have
- to be changed to _core.pyd as well, and we do the same
+ to be changed to _core.pyd as well, and we do the same
to the other extension modules. Now, we change our package hierarchy like
so:
- which is not what we want. But here enters the __init__.py
- magic: everything that is brought to the __init__.py namespace
+ which is not what we want. But here enters the __init__.py
+ magic: everything that is brought to the __init__.py namespace
can be accessed directly by the user. So, all we have to do is bring the
- entire namespace from _core.pyd to core/__init__.py.
- So add this line of code to soundscore__init__.py:
+ entire namespace from _core.pyd to core/__init__.py.
+ So add this line of code to soundscore__init__.py:
from _core import * @@ -208,10 +206,10 @@ with the additional benefit that we can easily add pure Python functions to any module, in a way that the user can't tell the difference between a C++ function and a Python function. Let's add a pure - Python function, echo_noise, to the filters - package. This function applies both the echo and noise - filters in sequence in the given sound object. We create - a file named sounds/filters/echo_noise.py and code our + Python function,echo_noise, to thefilters+ package. This function applies both theechoandnoise+ filters in sequence in the givensoundobject. We create + a file namedsounds/filters/echo_noise.pyand code our function:@@ -222,14 +220,14 @@ return s- Next, we add this line to soundsfilters__init__.py: + Next, we add this line to
soundsfilters__init__.py:from echo_noise import echo_noiseAnd that's it. The user now accesses this function like any other function - from the filters package: + from the
filterspackage:>>> import sounds.filters @@ -263,7 +261,7 @@We can do the same with classes that were wrapped with Boost.Python. Suppose - we have a class point in C++: + we have a class
pointin C++:@@ -277,7 +275,7 @@
If we are using the technique from the previous session, Creating - Packages, we can code directly into geom/__init__.py: + Packages, we can code directly into
geom/__init__.py:@@ -292,7 +290,7 @@ point.__str__ = point_str
- All point instances created from C++ will + All point instances created from C++ will also have this member function! This technique has several advantages:
- Now you create a file main.cpp, which contains the BOOST_PYTHON_MODULE
+ Now you create a file main.cpp, which contains the BOOST_PYTHON_MODULE
macro, and call the various export functions inside it.
@@ -427,17 +425,19 @@
exporting it to Python at the same time: changes in a class will only demand
the compilation of a single cpp, instead of the entire wrapper code.
-
-
If you're exporting your classes with Pyste,
- take a look at the --multiple option, that generates the
- wrappers in various files as demonstrated here.
-
-
-
This method is useful too if you are getting the error
- message "fatal error C1204:Compiler limit:internal structure
- overflow" when compiling a large source file, as explained
- in the FAQ.
-
+
+
+
If you're exporting your classes with Pyste,
+ take a look at the --multiple option, that generates
+ the wrappers in various files as demonstrated here.
+
+
+
+
This method is useful too if you are getting the
+ error message "fatal error C1204:Compiler limit:internal
+ structure overflow" when compiling a large source file,
+ as explained in the FAQ.
+