0

I have a very simple C++ class which owns a std::vector. I want to expose this class by SWIG to python :

Arr.hpp:

#include <vector>
class Arr
{
public:
  inline Arr() : _v() { }
  inline void add(double v) { _v.push_back(v); }
  inline double get(unsigned int i) const { return _v[i]; }
  inline const std::vector<double>& getVector() const { return _v; }
private:
  std::vector<double> _v;
};

arr.i:

%module pyarr

%include <std_vector.i>

namespace std {
%template(VectorDouble) vector<double>;
};

%include Arr.hpp
%{
  #include "Arr.hpp"
%}

Makefile:

swig -c++ -python -naturalvar -o arr_wrap.cpp arr.i
g++ -std=c++11 -fpic -shared arr_wrap.cpp -I/usr/include/python3.5m -o _pyarr.so

test_arr.py:

#!/usr/bin/python3

from pyarr import *

a = Arr()
a.add(1.2)
a.add(2.3)
print("v[0]=",a.get(0))
print("v[1]=",a.get(1))
print("v as vector=",a.getVector())
print("v=",a)

When I execute the test_arr.py script, I obtain:

python3 test_arr.py

v[0]= 1.2
v[1]= 2.3
v as vector= (1.2, 2.3)
v= <pyarr.Arr; proxy of <Swig Object of type 'Arr *' at 0x7f6f6fa4bf00> >

What I have to do to make my Arr class behaving like a python tuple ? So that the last line will be :

v= (1.2, 2.3)

[Edit]: My question is not only for display purpose, but also for plotting an histogram or initializing a numpy array, etc...

Note that, following the proposed answer here (How to use a Python list to assign a std::vector in C++ using SWIG?), I have tried with and without %naturalvar in swig command line.

McClain
  • 17
  • 4

1 Answers1

0

You could extend the class to include a __repr__ function so Python will display the Arr class as you want:

Updated arr.i:

%module pyarr

%{
    #include <string>
    #include <sstream>
    #include "Arr.hpp"
%}

%include <std_vector.i>
%include <std_string.i>

namespace std {
%template(VectorDouble) vector<double>;
};

%extend Arr {
    std::string __repr__()
    {
        std::ostringstream ss;
        auto v = $self->getVector();
        auto size = v.size();
        ss << "(";
        if(size > 0) {
            ss << v[0];
            for(size_t i = 1; i < size; ++i)
                ss << ", " << v[i];
        }
        ss << ")";
        return ss.str();
    }
}

%include "Arr.hpp"

Output of test_arr.py:

v[0]= 1.2
v[1]= 2.3
v as vector= (1.2, 2.3)
v= (1.2, 2.3)
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • Thank you very much Mark for your answer.. Your proposition answers my question but I really need to make Arr considered as a tuple. Not only for display purpose, But also for plotting an histogram or initializing a numpy array.I have edited my question to be more accurate. – McClain Dec 20 '20 at 12:37
  • @McClain You have a tuple with the getVector method. It can’t act as a class and a tuple at the same time. Maybe you want typemaps that convert input parameters from tuples to Arr and return types of Arr to tuples? – Mark Tolonen Dec 20 '20 at 16:44
  • @McClain. If you want to be able to output python tuples from C++ wrapping std::vector by another c++ class is not the way to go. As Mark suggests you should use typemaps, see https://stackoverflow.com/questions/52960876/tuple-is-returned-by-python-wrapper-generated-by-swig-for-a-c-vector. You could also look into `numpy.i` – Jens Munk Dec 22 '20 at 00:47