2014-10-04 3 views
0

C++에 클래스가 있다고 가정합니다. 그것은 파이썬에 대한 __getitem__ 기능을하기 위해서는 SomeType의 배열을 구현하고, 나는 these functions를 사용하여 slice의 인덱스를 얻을 수 있습니다이boost :: python에서 파이썬 슬라이스 객체를 처리하는 방법은 무엇입니까?

const SomeType& getitem(const MyArray *arr, PyObject *slice) { 
    // ??? 
} 

BOOST_PYTHON_MODULE(mymodule) 
{ 
    class_<MyArray>("MyArray") 
    .def("__getitem__", &getitem) 
    // probably some other methods... 
    ; 
} 

그런 짓을. 그러나 "Boost::Python is designed with the idea in mind that users never touch a PyObject*".

더 나은 '부스트 방법'이 있습니까?

답변

3

Boost.Python은 PyObject와 상호 작용하는 필요성을 최소화하도록 설계하고, 자주하여이 작업을 수행한다 : 높은 수준의 타입 래퍼를 제공

  • .
  • boost::python::object을 통해 파이썬 객체의 인터페이스에 대한 액세스를 허용합니다.

예를 들어 파이썬에서와 비슷한 방식으로 C++을 통해 파이썬 객체의 인터페이스에 액세스 할 수 있습니다. 길이 제로의 처리 None가 제공 될 때 기본값을 만들고,이 방법은 작동

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. 

동안, 많은 상용구 코드 발생하는 경향이있다 : 다음은 파이썬 slice 인스턴스를 참조하는 boost::python::objectstart 속성에 접근 보여줍니다 슬라이스 및 음수 인덱스를 양수 인덱스로 변환합니다. 이 경우 Boost.Python은 많은 상용구 코드를 제거하는 get_indices() 멤버 함수가있는 상위 수준 유형 래퍼 boost::python::slice을 제공합니다. 여기에 완전한 최소한의 예입니다

#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:] == []) 
+0

좋은 예! 슬라이스와 인덱스 (예 : counter [2 : -1] 및 counter [2])를 모두 처리 할 수 ​​있도록 확장 할 수 있습니까? – Felix

관련 문제