I have searched on the web and didn't get success. I'm wrapping the sample code below to Python (using SWIG):
class atomo {
public:
int i;
atomo(int a) {
i = a;
};
};
class funa {
public:
atomo *lista[3];
funa() {
lista[0] = new atomo(1);
lista[1] = new atomo(2);
lista[2] = new atomo(3);
};
};
But Python can't iterate over or access lista
using the comands
>>> test = myModule.funa()
>>> test.lista[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __iter__
TypeError: 'SwigPyObject' object is not subscriptable
>>> for i in test.lista:
>>> print(i)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __iter__
TypeError: 'SwigPyObject' object is not subscriptable
How can I make lista
iterable? There is a way to use Python lists instead of C++ arrays?
My Python version is 3.2 and I'm using SWIG 2.0.4 with g++ 4.6.1
Thanks
It's a little unclear from your question if you want to use std::vector
or an array of your own types.
For std::vector
, given some C++ like:
#include <vector>
#include <string>
struct foo {
std::string name;
};
inline std::vector<foo> test() {
std::vector<foo> ret;
foo instance;
instance.name = "one";
ret.push_back(instance);
instance.name = "two";
ret.push_back(instance);
return ret;
}
You can wrap it with %template
, pyabc.i
and std_vector.i
e.g.:
%module test
%{
#include "test.h"
%}
%include "pyabc.i"
%include "std_vector.i"
%include "test.h"
%template (FooVector) std::vector<foo>;
which will behave intuitively on the Python type. You'll need to call SWIG with something like:
swig -python -c++ -py3 -extranative test.i
If the idea is to wrap a "custom" container to behave intuitively on the Python side I gave a detailed example in a previous answer.
You might want to solve this on the Python side instead of the C++/SWIG side for simplicity.
# wrapper/facade
class Funa:
def __init__(self):
self._impl = myModule.funa() # _impl => implementation
def __iter__(self):
for i in xrange(3):
yield self._impl.lista[i]
test = Funa()
for x in test:
print(x)
A similar approach to larsmans is to have Funa.__iter__
return a generator object. Then you would only need to add to the interface SWIG creates. (With his wrapping, you would have to wrap every other method, or play with __getattr__
.) Roughly it would be like this
class Funa:
class FunaIter :
def __init__(self, parent) :
self.parent = parent
self.pos = 0
def __iter__(self) :
while self.pos < 3 :
yield self.parent.lista[self.pos]
self.pos += 1
def __iter__(self) :
return self.FunaIter(self)
This should be simpler to insert into your SWIG file using the %extend
and %pythoncode
directives.
Also, SWIG has wrappers for STL containers, so perhaps using those, you can easily obtain the necessary item getters.