Boost.Python的設計,以儘量減少需要與PyObject
互動,同時也經常完成此:
- 提供了更高級別的類型包裝。
- 允許通過關聯的
boost::python::object
訪問Python對象的接口。
例如,可以通過C++以類似於Python中的方式訪問Python對象的接口。下面演示訪問start
屬性boost::python::object
的指代一個Python slice
實例:
namespace python = boost::python;
python::object slice = get_slice_object();
python::object start = slice.attr("start");
std::size_t start_index = !start.is_none()
? python::extract<std::size_t>(start) // Extract index.
: 0; // Default.
雖然這種方法的工作原理,它趨向於導致多樣板代碼:當提供None
創建默認值,處理零長度切片,並將負向索引轉換爲正向索引。在這種情況下,Boost.Python提供了一個更高級別的包裝boost::python::slice
,該包裝具有get_indices()
成員函數,該函數將刪除大部分樣板代碼。這是一個完整的小例子:
#include <vector>
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>
#include <boost/python.hpp>
#include <boost/python/slice.hpp>
/// @brief Mockup class that creates a range from 0 to N.
struct counter
{
counter(std::size_t n)
{
data.reserve(n);
boost::copy(boost::irange(std::size_t(0), n), std::back_inserter(data));
}
std::vector<int> data;
};
/// @brief Handle slicing for counter object.
boost::python::list spam_getitem(
const counter& self,
boost::python::slice slice)
{
namespace python = boost::python;
python::list result;
// Boost.Python will throw std::invalid_argument if the range would be
// empty.
python::slice::range<std::vector<int>::const_iterator> range;
try
{
range = slice.get_indices(self.data.begin(), self.data.end());
}
catch (std::invalid_argument)
{
return result;
}
// Iterate over fully-closed range.
for (; range.start != range.stop; std::advance(range.start, range.step))
{
result.append(*range.start);
}
result.append(*range.start); // Handle last item.
return result;
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<counter>("Counter", python::init<int>())
.def("__getitem__", &spam_getitem)
;
}
互動用法:
>>> from example import Counter
>>> counter = Counter(5)
>>> assert(counter[:] == [0,1,2,3,4])
>>> assert(counter[:-2] == [0,1,2])
>>> assert(counter[-2:] == [3,4])
>>> assert(counter[::2] == [0,2,4])
>>> assert(counter[1::2] == [1,3])
>>> assert(counter[100:] == [])
很好的例子!這可以擴展來處理切片和索引(例如,計數器[2:-1]和計數器[2])? – Felix 2017-02-22 15:29:42