Boost Python 2: конструкторы с использованием `std::string &`

У меня есть устаревший код на 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);        
}

Скомпилируется, не беспокойтесь, но данные, которые загружаются, каким-то образом искажены, что наводит меня на мысль, что я делаю это ужасно неправильно.

Также я нашел это немного оффтопический SO-вопрос, который сказал мне, что у меня не может быть std::string &, потому что строки Python неизменяемы.

Итак, вывод: я понятия не имею, что теперь делать :( Кто-нибудь может мне помочь? Спасибо.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Возьмите в качестве эталона этот рабочий пример.

  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
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. Наслаждайтесь этим в питоне:
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. Это заканчивается ужасными ошибками.

tomascapek 08.04.2019 16:01
Ответ принят как подходящий

Итак, я нашел решение. Докажите, что я не прав, но я думаю, что то, чего я пытаюсь достичь, невозможно.

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!

Другие вопросы по теме