【问题标题】:Make C++ array of objects iterable in Python在 Python 中使 C++ 对象数组可迭代
【发布时间】:2012-02-12 09:17:11
【问题描述】:

我在网上搜索并没有成功。我将下面的示例代码包装到 Python(使用 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);
    };
};

但 Python 无法使用命令迭代或访问 lista

>>> 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

如何使lista 可迭代?有没有办法使用 Python 列表而不是 C++ 数组?

我的 Python 版本是 3.2,我正在使用 SWIG 2.0.4 和 g++ 4.6.1

谢谢

【问题讨论】:

  • 只是猜测:list(test.lista)

标签: c++ python arrays object swig


【解决方案1】:

如果您想使用std::vector 或您自己的类型的数组,您的问题有点不清楚。

对于std::vector,给定一些 C++ 之类的:

#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;
}

您可以使用%templatepyabc.istd_vector.i 来包装它,例如:

%module test

%{
#include "test.h"
%}

%include "pyabc.i"
%include "std_vector.i"

%include "test.h"

%template (FooVector) std::vector<foo>;

这将在 Python 类型上直观地表现。您需要通过以下方式调用 SWIG:

swig -python -c++ -py3 -extranative test.i

如果想法是包装一个“自定义”容器以在 Python 端直观地表现,我在之前的答案中给出了 detailed example

【讨论】:

    【解决方案2】:

    为简单起见,您可能希望在 Python 端而不是 C++/SWIG 端解决此问题。

    # 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)
    

    【讨论】:

    • @user1154091:只要在 Python 中保留内部循环,就不会获得太多速度。将内部循环移到 C++ 代码中以真正发挥作用。
    • @Sven Marnach:这只是一段显示相同错误的简单代码。我真实代码的瓶颈是atomo类的实例化
    • @CaioS.:我上面的评论是为了回应您(现已删除)您不喜欢这个答案的评论,因为它可能太慢了。
    【解决方案3】:

    larsmans 类似的方法是让Funa.__iter__ 返回一个生成器对象。然后您只需要添加到 SWIG 创建的界面。 (使用他的包装,您将不得不包装所有其他方法,或者使用__getattr__。)大致是这样的

    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)
    

    这应该更容易使用 %extend%pythoncode 指令插入到您的 SWIG 文件中。

    另外,SWIG has wrappers for STL containers,所以也许使用这些,您可以轻松获得必要的物品获取器。

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 2014-07-11
      • 2014-08-31
      • 2020-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-14
      • 2014-11-04
      相关资源
      最近更新 更多