Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Recipe 17.3. Exposing a C++ Library to Python


Credit: Ralf W. Grosse-Kunstleve, David Abrahams


Problem


You want to use a C++
library in Python. For example, you might have a fast
rational-numbers library, coded in C++, that you wish to wrap for use
from Python.


Solution


Boost, http://www.boost.org, is a
large free package with more than 50 fast and solid C++ libraries.
Among those libraries, we find both
Boost.Rational, a rational number library, and
Boost.Python, which makes it easy to turn any
other C++ library into a Python extension. So, we simply use the
latter to wrap the former:

#include <boost/python.hpp>
#include <boost/rational.hpp>
/* two specific conversion functions: rational to float and to str */
static double
as_float(boost::rational<int> const& self)
{
return double(self.numerator( )) / self.denominator( );
}
static boost::python::object
as_str(boost::rational<int> const& self)
{
using boost::python::str;
if (self.denominator( ) == 1) return str(self.numerator( ));
return str(self.numerator( )) + "/" + str(self.denominator( ));
}
/* the 'rational' Python extension module, with just one class in it: */
BOOST_PYTHON_MODULE(rational)
{
boost::python::class_<boost::rational<int> >("int")
.def(boost::python::init<int, optional<int> >( ))
.def("numerator", &boost::rational<int>::numerator)
.def("denominator", &boost::rational<int>::denominator)
.def("_ _float_ _", as_float)
.def("_ _str_ _", as_str)
.def(-self)
.def(self + self)
.def(self - self)
.def(self * self)
.def(self / self)
.def(self + int( ))
.def(self - int( ))
.def(self * int( ))
.def(self / int( ))
.def(int( ) + self)
.def(int( ) - self)
.def(int( ) * self)
.def(int( ) / self)
;
}


Discussion


Once you have built and installed the rational
extension shown in this recipe's Solution, you can
use it to perform simple, natural tasks, such as:

>>> import rational
>>> x = rational.int(1, 3)
>>> y = rational.int(-2, 4)
>>> print "x =", x
x = 1/3
>>> print "y =", y
y = -1/2
>>> print "x+y =", x+y
x+y = -1/6
>>> print "x*2 =", x * 2
x*2 = 2/3
>>> print "3/y =", 3 / y
3/y = -6

Compiling and linking Boost.Python extensions is supported by the
Boost.Build tool; we do not cover that topic here. Extensive
documentation is available online at the Boost site. Such tools as
make and SCons are also popular
for software compilation and linking tasks, including tasks that
involve Boost.

The Solution's code shows off a few of
Boost.Python's powerful features. Consider the
snippet:

BOOST_PYTHON_MODULE(rational)
{
class_<boost::rational<int> >("int")
...

The BOOST_PYTHON_MODULE macro takes a module name
as a parameter, and a module body immediately afterwards within
braces, and does all that's needed to make a module
we can import from Python.

The class_ template, instantiated with the
boost::rational type as a parameter and
"called" with the string argument
"int", does all we need to have as part of our
module a Python-usable class, named rational.int,
each of whose instances wraps an instance of the
boost::rational class. The type
boost::rational is itself a template, and we
instantiate that template with int as a parameter,
to use int as the type of each rational
number's numerator and denominator.

If we stopped here, wrapping a C++ class in the
class_ template, and exposing the wrapper without
adding any more to it, we'd have a rather empty type
available on the Python side. It would have no constructor (save for
the default argument-less one), no methods, and no attributes. To
remedy this, the Solution code continues with several
.def(...) calls, which are
chained: each call enriches the object, and also
returns it, so you can just string such calls one after the other.
The methods we add with all those def calls
include a constructor (which uses the init
template), then a couple of ordinary methods that delegate to the
methods of the same names in the wrapped class (accessors to the
numerator and denominator parts of a rational number), and then a
couple of type-conversion special methods for which
we've previously coded corresponding functions (just
before the BOOST_PYTHON_MODULE macro). Note, in
particular, that the implementation of the as_str
function is so concise because it makes full use of
Boost.Python's object
interfaceit's almost like writing Python in
C++.

The baker's dozen of .def(...)
calls that begins with:

    .def(-self)

and proceeds all the way to:

    .def(int( ) / self)

exposes all the arithmetic special methods for our new
rational.int classunary minus (_
_neg_ _
), and the four operations, each in three
versionsbetween two instances of our class, and between such
instances and ints on either side (_
_add_ _
, _ _radd_ _, etc.). The magic is
performed using expression templates, a
technique originally developed for optimizing high-performance matrix
algebra expressions. Boost.Python's use of
expression templates has a different purpose, but it certainly comes
in handy anyway!

A comprehensive rational number extension would require more
functionalitycomparison operators, _ _repr_
_
, _ _hash_ _, support for pickling, and
so on. A more complete implementation, one that is actively used in
applications, can be found at http://cvs.sourceforge.net/viewcvs.py/cctbx/boost_adaptbx/,
in the file rational_ext.cpp.


See Also


Boost's site is http://www.boost.org; the rational number
library Boost.Rational, is at http://www.boost.org/libs/rational;
Boost.Python is at http://www.boost.org/libs/python.


/ 394