Is there a way for C++ objects, wrapped by SWIG, to carry custom Python data with them as they pass back and forth between C++ and Python? Example:
example.h
class MyClass
{
public:
int foo;
};
// Black box functions.
// Only thing guaranteed is that开发者_JAVA百科 the last object handed to consume
// will be returned by eject.
void consume(MyClass *obj);
MyClass *eject();
example.i
%module Example
%{
#include "example.h"
%}
%include "example.h"
test.py
import Example
a = Example.MyClass()
a.bar = "Puppies"
Example.consume(a)
b = Example.eject()
## Should output "Puppies"
print b.bar
The current output is an "AttributeError: bar".
Is there anyway to get this kind of functionality? If SWIG's_getattr_ functions for MyClass could be customized, then perhaps unknown attributes could be stored and loaded from an internal PyObject* (either by having SWIG sub-class MyClass automatically, or by having such an object already present in MyClass)?
Thank you!
This is the only (partial) solution I've come up with so far:
class MyClass
{
...
MyClass() : data(NULL) {}
~MyClass() {if(data) Py_DECREF(data);}
PyObject *data;
};
%typemap(in) PyObject* data {
if(arg1 && arg1->data != NULL)
Py_DECREF(arg1->data);
$1 = $input;
Py_XINCREF($1);
}
%typemap(out) PyObject* data {
$result = $1;
}
Problems:
1) SWIG sets $1
to NULL
, instead of the existing value, and I could not find an official way to access the existing value inside a typemap. The above depends on SWIG naming the object (MyClass *) as arg1. Works, but probably not portable across future SWIG versions.
2) The Python code must be a.data.bar = "Puppies"
. This is okay, but not perfect.
3) It requires that the class have a data
member. This is okay for my current needs and can be handled by a base class.
4) The class's destructor must also be aware of data, and clean it up. Again, okay for my current needs, but somewhat cumbersome.
精彩评论