There is an easy way to make python properties from methods with swig.
Suppose C++ code Example.h:
C++ header
class Example{
public:
void SetX(int x);
int GetX() const;
};
Lets convert this setter and getter to python propery 'x'. The trick is in .i file. We add some "swiggy" inline python code (with %pythoncode) that is inserted in a body of a resulting python class (in the auto-generated python code).
Swig wrapping Example.i
%module example
%{
#include "example.h"
%}
class Example{
public:
void SetX(int x);
int GetX() const;
%pythoncode %{
__swig_getmethods__["x"] = GetX
__swig_setmethods__["x"] = SetX
if _newclass: x = property(GetX, SetX)
%}
};
Check the python code:
python test code
import example
test = example.Example()
test.x = 5
print "Ha ha ha! It works! X = ", repr(test.x)
That is it!
Make it simplier!
There is no need to rewrite a class definition. Thanks to Joshua advice, one could use SWIG directive %extend ClassName { }.
Swig wrapping Example.i
%module example
%{
#include "example.h"
%}
%extend Example{
%pythoncode %{
__swig_getmethods__["x"] = GetX
__swig_setmethods__["x"] = SetX
if _newclass: x = property(GetX, SetX)
%}
};
Hiding setter and getter functions
As one may see, test.GetX() and test.SetX() are still in place after conversion. One can hide them by:
a) Rename functions by using %rename, add '_' in the beginning thus making methods "private" for python. In the a SWIG interface .i
Example.i
...
class Example{
%rename(_SetX) SetX(int);
%rename(_GetX) GetX();
...
(%rename may be placed in some separated place to save the possibility to convert this class to other languages, which don't need these '_')
b) or one can play with %feature("shadow")
Why is it so?
Why do we have to use such things to convert methods to a property by using SWIG?
As it was said, SWIG selfishly overrides _setattr_, so one have to use _swig_getmethods_ and _swig_setmethods_ to register functions and stay in the swig way.
Why may one prefer this way?
The methods listed above, especially with PropertyVoodoo are... It is like burning the house to fry an egg. Also it breaks the classes layout, as one have to create inherited classes to make python properties from C++ methods. I mean if class Cow returns class Milk and the inherited class is MilkWithProperties(Milk), how to make Cow to produce MilkWithProperties?
This approach allows one to:
- explicitly control what C++ methods to convert to python properties
- conversion rules are located in swig interface(*.i) files, the place where they are supposed to be
- one resulting autogenerated .py file
- stay in the swig syntax of insertions in swig generated .py file
- %pythoncode is ignored if one wraps library to other languages
Update
In a newer version SWIG abandoned _swig_property so just use property. It works with old version of swig the same. I've changed the post.