【问题标题】:Boost Python 2: Constructors using `std::string &`Boost Python 2:使用`std::string &`的构造函数
【发布时间】:2019-08-27 11:40:51
【问题描述】:

我有一个 C++ 遗留代码(编辑起来会很痛苦),出于速度原因,我需要在 Python 2 中使用它。

我有两节课。一个负责从内存中加载大量数据,形式为std::string,并将其转换为内部表示MiddleClass。第二个是将其从内部表示 MiddleClass 转换回 std::string

 class Load {
     Load(const std::string & data) { ... };
     MiddleClass load() { ... };
 };

 class Save {
     Save(std::string & data) { .... };
     void save(const MiddleClass & middleclass) { ... };
 };

我的目标是,像这样在 Python 2 中使用这个设置:

import datahandler # my lib
import requests

request = request.get("url-to-data")
loader = datahandler.Load(request.content) # my C++ class Load
internal_representation = loader.load()

.
.
.

result_variable = str() # or None or something not important
saver = datahandler.Save(result_variable) # my C++ class Save
saver.save(internal_representation)

我怎样才能做到这一点?


我从一开始就遇到了麻烦。

简单变体:

BOOST_PYTHON_MODULE(datahandler)
{
     class_<MiddleClass>("MiddleClass");\
     // some .defs - not important

     class <Load>("Load", init<const std::string &>())
         .def("load". &Load::load);

     class <Save>("Save", init<std::string &>())
         .def("save". &Save::save);        
}

会编译,不用担心,但是加载的数据会以某种方式被破坏,这让我想到,我做的非常错误。

我还发现了this 有点离题的 SO 问题,它告诉我,我不能拥有std::string &amp;,因为 Python 字符串是不可变的。

所以结论:我现在不知道该怎么做:(这里有人可以帮助我吗?谢谢。

【问题讨论】:

    标签: python c++ python-2.7 boost-python


    【解决方案1】:

    将此工作示例作为参考。

    1. 定义您的 C++ 类。例如:
    
    class MiddleClass {
    public:
        explicit MiddleClass(const std::string& data) : parent_data_(data) {}
    
        void print() {
            std::cout << parent_data_ << std::endl;
        }
    
    private:
        std::string parent_data_;
    };
    
    class Loader {
    public:
        explicit Loader(const std::string& data) :
            data_(data){
    
            };
    
        MiddleClass load() {
            return MiddleClass(data_);
        };
    
    private:
        std::string data_;
    };
    
    
    1. 创建增强绑定
    boost::python::class_<MiddleClass>("MiddleClass",
         boost::python::init<const std::string&>(boost::python::arg("data"), ""))
         .def("print_data", &MiddleClass::print);
    
    boost::python::class_<Loader>("Loader", 
         boost::python::init<const std::string&>(boost::python::arg("data"), ""))
         .def("load", &Loader::load);
    
    1. 在正确的 python 站点包中安装您的库。
    2. 在 python 中享受它:
    from my_cool_package import MiddleClass, Loader
    example_string = "whatever"
    loader = Loader(data=example_string)
    
    # Get the middle class
    middle_class = loader.load()
    
    # Print the data in the middle class
    middle_class.print_data()
    

    预期输出:

    whatever
    

    【讨论】:

    • 这只能解决我一半的麻烦。我仍然对Save 课程有疑问。它以可怕的错误结束。
    【解决方案2】:

    所以,我找到了解决方案。证明我错了,但我认为,我想要实现的目标是不可能的。

    Python 具有不可变的字符串,因此将字符串的“引用”传递给函数并期望能够从函数内部对其进行更改是无效的。

    以这段代码为例:

    variable = "Hello"
    
    def changer(var):
        var = "Bye"
    
    changer(variable)
    
    print(variable)
    

    打印“你好”。在 Python 中,你不能让它以不同的方式工作。 (虽然准确地说,它仍然是作为引用传递的,但是当你修改 Python 字符串时,你只是创建一个新的和一个新的引用)。

    那么,如何解决这个问题?

    简单!创建一个 C++ 包装器,它将处理 std::string 上的传递引用并返回结果字符串的副本。不是很有效,但你可能无法让它变得更好。

    SaveWrapper类的示例代码:

    class SaveWrapper {
        public:
           // some constructor
           std::string save(MiddleClass & value) {
               std::string result;
    
               Save saver(result);
               saver.save(value);
    
               return result;
           }
    };
    

    可以轻松“移植”到 Python!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 2014-09-21
      • 2015-04-26
      • 1970-01-01
      相关资源
      最近更新 更多