4

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

1
  • Just a guess: list(test.lista) Commented Jan 17, 2012 at 15:09

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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)

3 Comments

@user1154091: As long as you keep the inner loops in Python, you won't gain too much speed. Move the inner loops to the C++ code to really make a difference.
@Sven Marnach: This is just a simple piece of code that shows the same error. The bottleneck of my real code is the instanciation of the class atomo
@CaioS.: My comment above was in response to your (now deleted) comment that you don't like this answer since it might be too slow.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.