У меня есть устаревший код на 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 неизменяемы.
Итак, вывод: я понятия не имею, что теперь делать :( Кто-нибудь может мне помочь? Спасибо.






Возьмите в качестве эталона этот рабочий пример.
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_;
};
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);
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
Итак, я нашел решение. Докажите, что я не прав, но я думаю, что то, чего я пытаюсь достичь, невозможно.
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!
Это решает только половину моей проблемы. У меня все еще есть проблемы с классом
Save. Это заканчивается ужасными ошибками.