tutorial.qbk

来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 1,973 行 · 第 1/5 页

QBK
1,973
字号
[library python    [version 1.0]    [authors [de Guzman, Joel], [Abrahams, David]]    [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams]    [category inter-language support]    [purpose        Reflects C++ classes and functions into Python    ]    [license        Distributed under the Boost Software License, Version 1.0.        (See accompanying file LICENSE_1_0.txt or copy at        <ulink url="http://www.boost.org/LICENSE_1_0.txt">            http://www.boost.org/LICENSE_1_0.txt        </ulink>)    ]][/ QuickBook Document version 0.9 ][def __note__       [$images/note.png]][def __alert__      [$images/alert.png]][def __tip__        [$images/tip.png]][def :-)            [$images/smiley.png]][def __jam__        [$images/jam.png]][section QuickStart]The Boost Python Library is a framework for interfacing Python andC++. It allows you to quickly and seamlessly expose C++ classesfunctions and objects to Python, and vice-versa, using no specialtools -- just your C++ compiler. It is designed to wrap C++ interfacesnon-intrusively, so that you should not have to change the C++ code atall in order to wrap it, making Boost.Python ideal for exposing3rd-party libraries to Python. The library's use of advancedmetaprogramming techniques simplifies its syntax for users, so thatwrapping code takes on the look of a kind of declarative interfacedefinition language (IDL).[h2 Hello World]Following C/C++ tradition, let's start with the "hello, world". A C++Function:    char const* greet()    {       return "hello, world";    }can be exposed to Python by writing a Boost.Python wrapper:    #include <boost/python.hpp>    BOOST_PYTHON_MODULE(hello_ext)    {        using namespace boost::python;        def("greet", greet);    }That's it. We're done. We can now build this as a shared library. Theresulting DLL is now visible to Python. Here's a sample Python session:[python]    >>> import hello_ext    >>> print hello.greet()    hello, world[c++][:['[*Next stop... Building your Hello World module from start to finish...]]][endsect][section:hello Building Hello World][h2 From Start To Finish]Now the first thing you'd want to do is to build the Hello World module andtry it for yourself in Python. In this section, we will outline the stepsnecessary to achieve that. We will use the build tool that comes bundledwith every boost distribution: [*bjam].[note [*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 showsthat 90% of the "I can't build Boost.Python" problems come from peoplewho had to use a different tool.]We will skip over the details. Our objective will be to simply createthe hello world module and run it in Python. For a complete reference tobuilding Boost.Python, check out: [@../../../building.htmlbuilding.html]. After this brief ['bjam] tutorial, we should have builtthe DLLs and run a python program using the extension.The tutorial example can be found in the directory:[^libs/python/example/tutorial]. There, you can find:* hello.cpp* hello.py* JamrootThe [^hello.cpp] file is our C++ hello world example. The [^Jamroot] isa minimalist ['bjam] script that builds the DLLs for us. Finally,[^hello.py] is our Python program that uses the extension in[^hello.cpp].Before anything else, you should have the bjam executable in your boostdirectory or somewhere in your path such that [^bjam] can be executed inthe command line. Pre-built Boost.Jam executables are available for mostplatforms. The complete list of Bjam executables can be found[@http://sourceforge.net/project/showfiles.php?group_id=7586 here].[h2 Let's Jam!]__jam__[@../../../../example/tutorial/Jamroot Here] is our minimalist Jamrootfile. Simply copy the file and tweak [^use-project boost] to where yourboost root directory is and your OK.The comments contained in the Jamrules file above should be sufficientto get you going.[h2 Running bjam]['bjam] is run using your operating system's command line interpreter.[:Start it up.]A file called user-config.jam in your home directory is used toconfigure your tools. In Windows, your home directory can be found bytyping:[preECHO %HOMEDRIVE%%HOMEPATH%]into a command prompt window. Your file should at least have the rulesfor your compiler and your python installation. A specific example ofthis on Windows would be:[pre#  MSVC configurationusing msvc : 8.0 ;#  Python configurationusing python : 2.4 : C:/dev/tools/Python/ ;]The first rule tells Bjam to use the MSVC 8.0 compiler and associatedtools. The second rule provides information on Python, its version andwhere it is located. The above assumes that the Python installation isin [^C:/dev/tools\/Python/]. If you have one fairly "standard" pythoninstallation for your platform, you might not need to do this.Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial]where the tutorial [^"hello.cpp"] and the [^"Jamroot"] is situated.Finally:    bjamIt should be building now:[precd C:\dev\boost\libs\python\example\tutorialbjam...patience......found 1101 targets......updating 35 targets...]And so on... Finally:[pre   Creating library /path-to-boost_python.dll/   Creating library /path-to-'''hello_ext'''.exp/'''**passed**''' ... hello.test...updated 35 targets...]Or something similar. If all is well, you should now have built the DLLs andrun the Python program.[note Starting from Boost 1.35, bjam erases the generated executables(e.g. pyd file) after the test has concluded to conserve disk space.To keep bjam from doing that, pass --preserve-test-targets to bjam.][:[*There you go... Have fun!]][endsect][section:exposing Exposing Classes]Now let's expose a C++ class to Python.Consider a C++ class/struct that we want to expose to Python:    struct World    {        void set(std::string msg) { this->msg = msg; }        std::string greet() { return msg; }        std::string msg;    };We can expose this to Python by writing a corresponding Boost.PythonC++ Wrapper:    #include <boost/python.hpp>    using namespace boost::python;    BOOST_PYTHON_MODULE(hello)    {        class_<World>("World")            .def("greet", &World::greet)            .def("set", &World::set)        ;    }Here, we wrote a C++ class wrapper that exposes the member functions[^greet] and [^set]. Now, after building our module as a shared library, wemay use our class [^World] in Python. Here's a sample Python session:[python]    >>> import hello    >>> planet = hello.World()    >>> planet.set('howdy')    >>> planet.greet()    'howdy'[section Constructors]Our previous example didn't have any explicit constructors.Since [^World] is declared as a plain struct, it has an implicit defaultconstructor. Boost.Python exposes the default constructor by default,which is why we were able to write    >>> planet = hello.World()We may wish to wrap a class with a non-default constructor. Let usbuild on our previous example:[c++]    struct World    {        World(std::string msg): msg(msg) {} // added constructor        void set(std::string msg) { this->msg = msg; }        std::string greet() { return msg; }        std::string msg;    };This time [^World] has no default constructor; our previouswrapping code would fail to compile when the library tried to exposeit. We have to tell [^class_<World>] about the constructor we want toexpose instead.    #include <boost/python.hpp>    using namespace boost::python;    BOOST_PYTHON_MODULE(hello)    {        class_<World>("World", init<std::string>())            .def("greet", &World::greet)            .def("set", &World::set)        ;    }[^init<std::string>()] exposes the constructor taking in a[^std::string] (in Python, constructors are spelled"[^"__init__"]").We can expose additional constructors by passing more [^init<...>]s tothe [^def()] member function. Say for example we have another Worldconstructor taking in two doubles:    class_<World>("World", init<std::string>())        .def(init<double, double>())        .def("greet", &World::greet)        .def("set", &World::set)    ;On the other hand, if we do not wish to expose any constructors atall, we may use [^no_init] instead:    class_<Abstract>("Abstract", no_init)This actually adds an [^__init__] method which always raises aPython RuntimeError exception.[endsect][section Class Data Members]Data members may also be exposed to Python so that they can beaccessed as attributes of the corresponding Python class. Each datamember that we wish to be exposed may be regarded as [*read-only] or[*read-write].  Consider this class [^Var]:    struct Var    {        Var(std::string name) : name(name), value() {}        std::string const name;        float value;    };Our C++ [^Var] class and its data members can be exposed to Python:    class_<Var>("Var", init<std::string>())        .def_readonly("name", &Var::name)        .def_readwrite("value", &Var::value);Then, in Python, assuming we have placed our Var class inside the namespacehello as we did before:[python]    >>> x = hello.Var('pi')    >>> x.value = 3.14    >>> print x.name, 'is around', x.value    pi is around 3.14Note that [^name] is exposed as [*read-only] while [^value] is exposedas [*read-write].    >>> x.name = 'e' # can't change name    Traceback (most recent call last):      File "<stdin>", line 1, in ?    AttributeError: can't set attribute[endsect][section Class Properties]In C++, classes with public data members are usually frownedupon. Well designed classes that take advantage of encapsulation hidethe class' data members. The only way to access the class' data isthrough access (getter/setter) functions. Access functions expose classproperties. Here's an example:[c++]    struct Num    {        Num();        float get() const;        void set(float value);        ...    };However, in Python attribute access is fine; it doesn't neccessarily breakencapsulation to let users handle attributes directly, because theattributes can just be a different syntax for a method call. Wrapping our[^Num] class using Boost.Python:    class_<Num>("Num")        .add_property("rovalue", &Num::get)        .add_property("value", &Num::get, &Num::set);And at last, in Python:[python]    >>> x = Num()    >>> x.value = 3.14    >>> x.value, x.rovalue    (3.14, 3.14)    >>> x.rovalue = 2.17 # error!Take note that the class property [^rovalue] is exposed as [*read-only]since the [^rovalue] setter member function is not passed in:[c++]    .add_property("rovalue", &Num::get)[endsect][section Inheritance]In the previous examples, we dealt with classes that are not polymorphic.This is not often the case. Much of the time, we will be wrappingpolymorphic classes and class hierarchies related by inheritance. We willoften have to write Boost.Python wrappers for classes that are derived fromabstract base classes.Consider this trivial inheritance structure:    struct Base { virtual ~Base(); };    struct Derived : Base {};And a set of C++ functions operating on [^Base] and [^Derived] objectinstances:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?