I am creating Python interfaces to some C++ code that I cannot change, using SWIG. One of the C++ classes has a constructor that creates a partially initialized object that cannot be used as yet, an initialization function has to be called on it first. I want to remedy this in Python by providing an alternative constructor that takes care of doing both things (acquisition and initialization) at the same time. Let's say in C++ I have
class X {
public:
X() {...}
void init(T a) {...}
...
};
In C++ I have to instantiate X as
X x;
x.init(a);
In Python I would like to do
x = X(a)
My solution is a hack that depends on the target language and the specific way SWIG generates the wrapper code: in my .i file I have
%inline %{
X* new_X(T a) {
X* ret = new X();
ret->init(a);
return ret;
}
%nodefaultctor X;
class X {
public:
...
%extend {
%pythoncode {
def __init__(self, *args):
this = _modulename.new_X(*args)
try:
self.this.append(this)
except:
self.this = this
}
}
};
This works fine, but it is not very satisfactory:
This seems to be a relatively common use case, so does anyone know if there is a standard way?
The current answer by V-master does not work as is. But it can be made to work:
%ignore X::X();
// declaration of class X, e.g. %include X.h
%extend X {
X(T a) {
X* newX = new X();
newX->init(a);
return newX;
}
};
Admittedly, this looks a little dubious, but it works, and is essentially an example from the SWIG documentation here.
It is important to note that:
%extend works with both C and C++ code. It does not modify the underlying object in any way---the extensions only show up in the Python interface.
So what this really does is to create a method (not even a class method, actually) that creates a new instance of X
, calls init(a)
on it and returns it. Because the syntax somewhat resembles a constructor, SWIG will wrap it as such.