如何在C++ __getitem__函数中处理切片(供SWIG使用)
我正在为一个扩展了std::vector
的C++类开发Python绑定。为了让这个类在Python中支持下标操作,我添加了一个__getitem__
函数,代码大致如下(我省略了不相关的代码和错误处理部分):
class Column;
typedef vector<Column*> MetaDataBase;
class MetaData : public MetaDataBase {
public:
#ifdef SWIGPYTHON
Column* __getitem__(int i) { return (*this)[i]; }
#endif
};
这个代码在Python中可以正常访问单个元素,但对于切片操作就不行了。
好的,我明白我需要把函数的参数类型改成PyObject *
,并使用PySlice_Check
来检查这个函数是否应该返回一个PyList
。
这样做没问题。但因为有时候我需要从这个函数返回PyList
,所以__getitem__
的返回值类型也必须是PyObject*
,而我不能依赖SWIG来把我的C++类型(Column *
)转换成一个包装类。此外,在创建切片的时候,我需要“手动”把Column*
转换成PyObject*
,然后再插入到PyList中。
我该怎么做呢?
1 个回答
3
我觉得对于std::vector
,用SWIG和Python可以有一个更简单的解决方案。SWIG生成的Python代码已经很好地支持了一些标准模板库(STL)容器。
如果你在模块接口的开头加上:
%include "pyabc.i"
%include "std_vector.i" // Assuming you don't already
然后在某个地方,如果你还没有这样做:
%template(MetaDataBase) std::vector<Column*>;
这样做会让包装后的std::vector
符合Python的可变序列的要求。(我觉得这应该足够让你在Python那边实现你想要的功能,可能还需要在调用SWIG时加上-extranative
选项)。
另外值得注意的是,对于你当前的__getitem__
,你可以在SWIG接口文件中用类似下面的方式声明和定义:
%extend MetaData {
Column* __getitem__(int i) { return (*self)[i]; }
};
这样可以让你在不“污染”你“正常”的头文件的情况下,添加SWIG和Python特定的代码。