Wrap C++ in a Python object
Aims
- Use the C++ code from a nice Python interface
Learning outcomes
- Defining classes in Python
Subprocesses in Python
We have compiled a C++ program and produced an executable myvicsek. We are running it from the shell and then retrieving the date from Python. Could we streamline the process a bit?
The first thing we could do is tho make our makefile take some external parameters from input, so that we do not need to recompile it every time we change a parameter.
This is easily done: the main function takes default inputs int argc, char* argv[] which are :
- the number of input arguments
- an array of input arguments (as sequence of characters)
Let us consider the simple case in which we only want one parameter in input, the noise strength.
We can do the following:
#include <iostream>
#include <cstdlib> // For std::stof (string to float)
int main(int argc, char* argv[]) {
// Convert the string argument to a float
double noiseStrength = std::stof(argv[1]);
// rest of main
// ...
return 0;
}Once this is done, we can recompile and run
./myvicsek 0.15to run our program at noise 0.15. But could we do this from python instead?
A dedicated module exists, called subprocess. It allows us to spawn a new process (our C++ program) from another process (e.g. a Python program).
import subprocess
# Define the command and arguments inside a list
command = ['./myvicsek', '0.14']
# Call the C++ program via subprocess
result = subprocess.run(command, capture_output=True, text=True)
# Print the output
print("Standard Output:", result.stdout)
print("Standard Error:", result.stderr)Wrap into a Python Class
Even more interesting would be to hide all this technical detail and simply be able to do the following:
import pyvicsek
model = pyvicsek.Wrapper(noise=0.15)
model.run()This code assumes that in our module pyvicsek there is something named Wrapper which takes a named parameter noise and a has an attached method called run(). Byt clearly this does not exist… yet!.
To make the code above valid we simply need to create a custom Python class. Classes in Python are very similar to C++, but much simpler.
The following analogies hold:
- member variables are called attributes
- member functions are called methods
- all attributes and methods are public
- C++’s
thisis conventionally calledself - C++’s
.and->are just. - the constructor is a hidden method always called
__init__()
Python classes are in general quite simpler than their C++ counterparts: there is no need for header files.
Our simple Wrapper class does not need to do much: it takes a parameter in input and then runs the code. However we need to give it some structure
class Wrapper:
def __init__(self, noise=0.1):
# code to initalise the object
def run(self):
# code to runNotice that the two methods (member functions) take self explicitly as their first parameter: this makes it possible for them to directly refer to the class instance inside their code. For example, the constructor __init__ can store the noise level by
self.noise = noiseand the method run() can refer to it, for example by using subprocess to run a local executable
def run(self):
command = ["absolute/path/to/myvicsek", str(self.noise)]
result = subprocess.run(command, capture_output=True, text=True)
return result