0

I have a legacy code in C++ (which would be a huge pain to edit) and I need to use it in Python 2 for speed reasons.

I have two classes. One is responsible for loading huge amount of data from memory, in a form of std::string and converting it to internal representation MiddleClass. Second one is converting it from internal representation MiddleClass back to std::string.

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

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

My goal is, to use this setup in Python 2 like this:

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)

How can I achieve this?


I've run into trouble, right from the start.

Simple variant:

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);        
}

Will compile, no worries, but data which are loaded are somehow mangled, which leads me to thinking, that I am doing it terribly wrongly.

Also I found this bit offtopic SO question, which told me, that I can't have std::string &, because Python strings are immutable.

So conclusion: I have no idea what to do now :( Can anyone here help me? Thanks.

2 Answers 2

0

Take as reference this working example.

  1. Define your C++ classes. For instance:

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. Create the boost bindings
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. Install your library in the right python site-package.
  2. Enjoy it in 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()

The expected output:

whatever
Sign up to request clarification or add additional context in comments.

1 Comment

This only solves half of my trouble. I still have issues with the Save class. It ends with terrible errors.
0

So, I have found a solution. Prove me wrong, but I think, that what am I trying to achieve is impossible.

Python has immutable strings, so passing a "reference" of string to function and expecting ability to change it from inside a function is simply not valid.

Take this code as an example:

variable = "Hello"

def changer(var):
    var = "Bye"

changer(variable)

print(variable)

Prints "Hello". In Python, you can't make it work differently. (although to be exact, it is still being passed as a reference, but when you modify Python string, you just create a new one and a new reference).

So, how to get arround this?

Simple! Create a C++ wrapper, that will handle passing reference on std::string and return copy of resulting string. Not very effective, but you probably can't make it better.

Sample code of SaveWrapper class:

class SaveWrapper {
    public:
       // some constructor
       std::string save(MiddleClass & value) {
           std::string result;

           Save saver(result);
           saver.save(value);

           return result;
       }
};

Which can be easily "ported" to Python!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.