Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to extend all classes in swig/python?

Tags:

python

swig

I have lots of C/C++ classes to export to python using Swig. I've noticed that by default, Swig doesn't generate a __hash__ method for wrapped classes, so the default hash gets used, which is the id of the wrapper object (i.e. its memory address or something like it). This means if I end up with two python objects wrapping the same C object, they hash differently in dicts and so on, which is weird and leads to hard-to-find bugs.

I can easily extend any class with a better __hash__:

%extend Foo {
   bool __eq__(const Foo &other) { return $self == &other; }
   bool __ne__(const Foo &other) { return $self != &other; }
   long __hash__() { return (long) $self; } // hash: just address of C struct
}

(I also think eq should by default compare based on the C struct address, rather than the wrapper's address.)

My question is this: Is there any way to tell Swig to extend all classes like this? Or do I have to do them one at a time?

I guess a secondary question would be: why doesn't swig just do this automatically? Is the default behavior useful? I don't find it to be.

like image 980
GaryO Avatar asked Feb 10 '14 23:02

GaryO


1 Answers

I am not aware of a way to do that, if only because it is rarely what you would want ("all classes" could include more than you realize and really intended). However, SWIG does support its own macro system, so you could probably do something like:

%define PY_HASHABLE(TypeName)
%extend TypeName {
   bool __eq__(const TypeName &other) { return $self == &other; }
   bool __ne__(const TypeName &other) { return $self != &other; }
   long __hash__() { return (long) $self; } // hash: just address of C struct
}
%enddef

Then you would do

#if defined(SWIGPYTHON) 
PY_HASHABLE(Foo)
PY_HASHABLE(Bar)
#endif

etc. You can have multiple extend clauses for a given class so the above does not interfere with other extensions.

like image 101
Oliver Avatar answered Oct 13 '22 08:10

Oliver