2013-04-05 6 views
14

मैं हस्ताक्षर के साथ एक समारोह मिल गया है:एक समारोह बूस्ट अजगर के साथ एक वेक्टर में लेने में एक अजगर सूची दूध पिलाने

function(std::vector<double> vector); 

और मैं यह सामने आ रहा है, लेकिन यह अजगर सूचियों में नहीं ले । मैंने अन्य SO उत्तरों को देखा है, और अधिकांश में बूस्ट :: पायथन :: सूचियों को लेने के लिए फ़ंक्शन को बदलना शामिल है, लेकिन मैं फ़ंक्शन को बदलना नहीं चाहता हूं। मुझे कल्पना है कि मैं इस फ़ंक्शन के चारों ओर एक साधारण रैपर लिखने के लिए vector_indexing_suite का उपयोग कर सकता हूं, लेकिन मेरे पास इस फ़ॉर्म के कई फ़ंक्शन हैं और प्रत्येक के लिए एक रैपर नहीं लिखेंगे। क्या पाइथन सूची स्वचालित रूप से बनाने का कोई तरीका है-> std :: वेक्टर मैपिंग होती है?

उत्तर

22

मूल कार्यों को संशोधित किए बिना इसे पूरा करने के कुछ समाधान हैं।

इसे बॉयलरप्लेट कोड की थोड़ी मात्रा और पाइथन पर पारदर्शिता के साथ पूरा करने के लिए, custom converter पंजीकृत करने पर विचार करें। Boost.Python C++ और पायथन प्रकारों के बीच जाने पर पंजीकृत कन्वर्टर्स का उपयोग करता है। बाइंडिंग बनाने के दौरान कुछ कनवर्टर्स पूरी तरह से बनाए जाते हैं, जैसे class_ एक प्रकार का निर्यात करते हैं।

निम्नलिखित पूर्ण उदाहरण iterable_converter प्रकार का उपयोग करता है जो python iterable protocol का समर्थन करते हुए एक पाइथन प्रकार से रूपांतरण कार्यों के पंजीकरण की अनुमति देता है। तार के std::vector<double>

  • 2-आयामी संग्रह: std::vector<std::vector<std::String> >
  • उपयोगकर्ता प्रकार का संग्रह: में निर्मित प्रकार के

    • संग्रह: उदाहरण के लिए रूपांतरण सक्षम std::list<foo>
    #include <iostream> 
    #include <list> 
    #include <vector> 
    #include <boost/python.hpp> 
    #include <boost/python/stl_iterator.hpp> 
    
    /// @brief Mockup model. 
    class foo {}; 
    
    // Test functions demonstrating capabilities. 
    
    void test1(std::vector<double> values) 
    { 
        for (auto&& value: values) 
        std::cout << value << std::endl; 
    } 
    
    void test2(std::vector<std::vector<std::string> > values) 
    { 
        for (auto&& inner: values) 
        for (auto&& value: inner) 
         std::cout << value << std::endl; 
    } 
    
    
    void test3(std::list<foo> values) 
    { 
        std::cout << values.size() << std::endl; 
    } 
    
    /// @brief Type that allows for registration of conversions from 
    ///  python iterable types. 
    struct iterable_converter 
    { 
        /// @note Registers converter from a python interable type to the 
        ///  provided type. 
        template <typename Container> 
        iterable_converter& 
        from_python() 
        { 
        boost::python::converter::registry::push_back(
         &iterable_converter::convertible, 
         &iterable_converter::construct<Container>, 
         boost::python::type_id<Container>()); 
    
        // Support chaining. 
        return *this; 
        } 
    
        /// @brief Check if PyObject is iterable. 
        static void* convertible(PyObject* object) 
        { 
        return PyObject_GetIter(object) ? object : NULL; 
        } 
    
        /// @brief Convert iterable PyObject to C++ container type. 
        /// 
        /// Container Concept requirements: 
        /// 
        /// * Container::value_type is CopyConstructable. 
        /// * Container can be constructed and populated with two iterators. 
        ///  I.e. Container(begin, end) 
        template <typename Container> 
        static void construct(
        PyObject* object, 
        boost::python::converter::rvalue_from_python_stage1_data* data) 
        { 
        namespace python = boost::python; 
        // Object is a borrowed reference, so create a handle indicting it is 
        // borrowed for proper reference counting. 
        python::handle<> handle(python::borrowed(object)); 
    
        // Obtain a handle to the memory block that the converter has allocated 
        // for the C++ type. 
        typedef python::converter::rvalue_from_python_storage<Container> 
                       storage_type; 
        void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes; 
    
        typedef python::stl_input_iterator<typename Container::value_type> 
                        iterator; 
    
        // Allocate the C++ type into the converter's memory block, and assign 
        // its handle to the converter's convertible variable. The C++ 
        // container is populated by passing the begin and end iterators of 
        // the python object to the container's constructor. 
        new (storage) Container(
         iterator(python::object(handle)), // begin 
         iterator());      // end 
        data->convertible = storage; 
        } 
    }; 
    
    BOOST_PYTHON_MODULE(example) 
    { 
        namespace python = boost::python; 
    
        // Register interable conversions. 
        iterable_converter() 
        // Build-in type. 
        .from_python<std::vector<double> >() 
        // Each dimension needs to be convertable. 
        .from_python<std::vector<std::string> >() 
        .from_python<std::vector<std::vector<std::string> > >() 
        // User type. 
        .from_python<std::list<foo> >() 
        ; 
    
        python::class_<foo>("Foo"); 
    
        python::def("test1", &test1); 
        python::def("test2", &test2); 
        python::def("test3", &test3); 
    } 
    

    इंटरएक्टिव उपयोग:

    >>> import example 
    >>> example.test1([1, 2, 3]) 
    1 
    2 
    3 
    >>> example.test1((4, 5, 6)) 
    4 
    5 
    6 
    >>> example.test2([ 
    ... ['a', 'b', 'c'], 
    ... ['d', 'e', 'f'] 
    ... ]) 
    a 
    b 
    c 
    d 
    e 
    f 
    >>> example.test3([example.Foo(), example.Foo()]) 
    2 
    

    इस दृष्टिकोण पर कुछ टिप्पणियां:

    • iterable_converter::convertible समारोह केवल अजगर सूची की इजाजत दी है, बजाय किसी भी प्रकार iterable प्रोटोकॉल का समर्थन करता है कि अनुमति देने के लिए बदला जा सकता है। हालांकि, परिणामस्वरूप विस्तार थोड़ा अस्पष्ट हो सकता है।
    • रूपांतरण C++ प्रकारों के आधार पर पंजीकृत हैं। इस प्रकार, पंजीकरण केवल एक बार किया जाना चाहिए, क्योंकि एक ही पंजीकृत रूपांतरण किसी भी निर्यात किए गए कार्यों पर चुना जाएगा जो सी ++ प्रकार को तर्क के रूप में स्वीकार करते हैं।
    • यह अनावश्यक प्रकारों को example एक्सटेंशन नामस्थान में पेश नहीं करता है।
    • मेटा-प्रोग्रामिंग बहु-आयामी प्रकारों को प्रत्येक आयाम प्रकार को दोबारा पंजीकृत करने की अनुमति दे सकता है। हालांकि, उदाहरण कोड पहले से ही जटिल है, इसलिए मैं जटिलता का एक अतिरिक्त स्तर जोड़ना नहीं चाहता था।

    वैकल्पिक दृष्टिकोण में शामिल हैं:

    • एक कस्टम समारोह या टेम्पलेट समारोह है कि प्रत्येक कार्य एक std::vector स्वीकार करने के लिए एक boost::python::list स्वीकार करता है बनाएँ। यह दृष्टिकोण बाइंडिंग को परिवर्तित किए जाने वाले प्रकारों की मात्रा के बजाए निर्यात किए जा रहे कार्यों की मात्रा के आधार पर स्केल करने का कारण बनता है।
    • Boost.Python vector_indexing_suite का उपयोग करना। *_indexing_suite कक्षाएं एक प्रकार का निर्यात करती हैं जो को पाइथन सूची या शब्दकोशों के कुछ अर्थशास्त्र से मेल खाने के लिए अनुकूलित करती है। इस प्रकार, पाइथन कोड को अब सटीक कंटेनर प्रकार को जानना है, जिसके परिणामस्वरूप कम-पायथनिक विस्तार होता है। उदाहरण के लिए, यदि std::vector<double>VecDouble के रूप में निर्यात किया जाता है, तो जिसके परिणामस्वरूप अजगर उपयोग होगा:

      v = example.VecDouble() 
      v[:] = [1, 2, 3] 
      example.test1(v) 
      

      हालांकि, निम्नलिखित कार्य नहीं करेगा क्योंकि सटीक प्रकार से मेल खाना चाहिए, वर्ग के निर्यात के रूप में केवल VecDouble और जो रूपांतरण दर्ज std::vector<double>: इस दृष्टिकोण कार्यों के बजाय प्रकार के पैमाने

      example.test1([4, 5, 6]) 
      

      है, यह एक कम pythonic विस्तार में परिणाम है और अनावश्यक प्रकार के साथ example नाम स्थान bloats।

  • संबंधित मुद्दे