I have a templated c++ array class which uses the standard vector class:
#include <vector>
#include <string>
using namespace std;
template<typename T>
class Array1D{
private:
vector<T> data_;
int xsize_;
public:
Array1D(): xsize_(0) {};
// creates vector of size nx and sets each element to t
Array1D(const int& nx, const T& t): xsize_(nx) {
data_.resize(xsize_, t);
}
T& operator()(int i) {return data_[i];}
T& operator[](int i) {return data_[i];}
};
My SWIG interface file looks like
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "test.h"
%}
%include "std_vector.i"
// Array 1D Typemaps
// typemaps for standard vector<double>
namespace std{
%template(DoubleVector) vector<double>;
%template(IntVector) vector<int>;
}
%include "test.h"
%template(intArray1D) Array1D<int>;
%template(doubleArray1D) Array1D<double>;
%rename(__getitem__) operator[];
%extend Array1D<T>{
T& __getitem__(int i) {
return (*self)[i];
}
}
After making the module, and create an Array1D in python, when I type in a[2] I get the following error:
TypeError: 'doubleArray1D' object does not support indexing
My guess is something is wrong with the extend part of my interface file. I don't think it is recognizing the type T. Any thoughts on how to get this to work?
Thanks in advance!
Extending a class is the same as inheriting a class. Let us see how inheritance works in Python. To inherit a class in Python, we pass the name of that class as a parameter while creating the child class. Let us understand this with an example. We first create a parent class, Desserts, with two methods - init and intro.
Still, there may be other lesser-used system calls that are only accessible through C. The os module in Python is one example. This is not an exhaustive list, but it gives you the gist of what can be done when extending Python using C or any other language.
What is SWIG In a nutshell, SWIG is a compiler that takes C/C++ declarations and creates a wrapper needed to access those declarations from other languages like Python, Tcl, Ruby etc. It normally required no changes in existing code and create an interface within a minute. Reasons for creating wrapper
So, why should you use C? Here are a few reasons why you might decide to build a Python C extension module: To implement new built-in object types: It’s possible to write a Python class in C, and then instantiate and extend that class from Python itself.
You can extend whole templates, without having to pick a specific type. For example, modifying your code as follows:
%module test
%{
#include <vector>
%}
%inline %{
template<typename T>
class Array1D{
private:
std::vector<T> data_;
size_t xsize_;
public:
Array1D(): xsize_(0) {};
// creates vector of size nx and sets each element to t
Array1D(const size_t& nx, const T& t): xsize_(nx) {
data_.resize(xsize_, t);
}
T& operator[](const size_t i) {return data_.at(i);}
};
%}
%extend Array1D {
T __getitem__(size_t i) {
return (*$self)[i];
}
}
%template(intArray1D) Array1D<int>;
%template(doubleArray1D) Array1D<double>;
Which works as you'd hope because SWIG itself expands and fills in the types for T
when it is generating the wrapper:
In [1]: import test
In [2]: a=test.intArray1D(10,1)
In [3]: a[0]
Out[3]: 1
In [4]: a[10]
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check
zsh: abort ipython
Note: I swapped to size_t
from int
because they're not synonyms always and .at()
instead of []
because the former will throw for an invalid index rather than invoke undefined behaviour. You can actually use SWIG's default exception library to do "smart" things with the exception for free:
%module test
%{
#include <vector>
%}
%include <std_except.i>
%inline %{
template<typename T>
class Array1D{
private:
std::vector<T> data_;
size_t xsize_;
public:
Array1D(): xsize_(0) {};
// creates vector of size nx and sets each element to t
Array1D(const size_t& nx, const T& t): xsize_(nx) {
data_.resize(xsize_, t);
}
T& operator[](const size_t i) {return data_.at(i);}
};
%}
%extend Array1D {
T __getitem__(size_t i) throw(std::out_of_range) {
return (*$self)[i];
}
}
%template(intArray1D) Array1D<int>;
%template(doubleArray1D) Array1D<double>;
Is sufficient (two lines of changes) to get a Python IndexError
instead of a C++ exception, crash or other UB.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With