提升Python 2:使用`std :: string&`

时间:2019-04-05 14:24:41

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

我有一个用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 &,因为Python字符串是不可变的。

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

2 个答案:

答案 0 :(得分:0)

以这个工作示例为参考。

  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

答案 1 :(得分:0)

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

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

以以下代码为例:

variable = "Hello"

def changer(var):
    var = "Bye"

changer(variable)

print(variable)

打印“ Hello”。在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!