让C++对象数组在Python中可迭代
我在网上搜索过,但没有找到解决办法。我把下面的示例代码用SWIG包装成了Python:
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。
谢谢!
3 个回答
0
一种和 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)
这样插入到你的 SWIG 文件里会更简单,可以使用 %extend
和 %pythoncode
指令。
另外,SWIG 对 STL 容器有封装,所以也许你可以利用这些,轻松获取所需的项目获取器。
1
为了简单起见,你可能想在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)
3
从你的问题来看,似乎不太清楚你是想使用 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;
}
你可以用 %template
、pyabc.i
和 std_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 中使用时也能很自然,我在之前的回答中提供了一个 详细示例。