Reputation: 781
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?
Upvotes: 3
Views: 2234
Reputation: 3043
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.
Upvotes: 6
Reputation: 2167
you can try something like this:
%ignore X::X();
%extend X {
X(T a) {
init(a);
}
};
this will hide default no-parameter constructor and add new that takes T
Downside is that if ignored one were doing something, then you would need to copy that into this new one as you cannot call other constructor from within same class constructor (unless you are using C++11)
Upvotes: 2