使用SWIG在Python中访问嵌套结构数组
我一直搞不清楚怎么访问下面这个嵌套结构中的数组元素 SubStatus。我好像能看到第一个元素,但不太明白怎么像列表那样强制索引。
非常感谢任何帮助。
status.h:
// Data Types
typedef char CHAR; // 8 bits signed
typedef short SHORT; // 16 bits signed
typedef long LONG; // 32 bits signed
typedef unsigned char UCHAR; // 8 bits unsigned
typedef unsigned short USHORT; // 16 bits usigned
#define FUNC_TYPE // built in C, leave reference as C
#define DLL_API extern FUNC_TYPE __declspec(dllimport)
// Sub Status Data
typedef struct
{
LONG xyz;
LONG abc;
} SUB_STATUS;
// Status Info
typedef struct
{
UCHAR qrs;
UCHAR tuv;
SUB_STATUS SubStatus[4];
LONG wxy;
} STATUS;
DLL_API SHORT GetStatus( STATUS *Status );
status.i
%module status
%{
/* Includes the header in the wrapper code */
#include "status.h"
%}
/* Parse the header file to generate wrappers */
%include "windows.i"
%include "typemaps.i"
%include "status.h"
1 个回答
1
你可以在不修改这个头文件的情况下,像这样包裹它:
%module status
%immutable;
%inline %{
template <typename Type, size_t N>
struct wrapped_array {
Type (&data)[N];
wrapped_array(Type (&data)[N]) : data(data) { }
};
%}
%mutable;
%{
#include "status.h"
%}
%include "typemaps.i"
%include "std_except.i"
// Only expose a reduced STATUS, without the Array:
typedef struct
{
UCHAR qrs;
UCHAR tuv;
LONG wxy;
} STATUS;
%extend wrapped_array {
inline size_t __len__() const { return N; }
inline const Type& __getitem__(size_t i) const throw(std::out_of_range) {
if (i >= N || i < 0)
throw std::out_of_range("out of bounds access");
return $self->data[i];
}
inline void __setitem__(size_t i, const Type& v) throw(std::out_of_range) {
if (i >= N || i < 0)
throw std::out_of_range("out of bounds access");
$self->data[i] = v;
}
}
%template (SubStatusArray) wrapped_array<SUB_STATUS,4>;
// Hide the real array in our helper
%extend STATUS {
wrapped_array<SUB_STATUS,4> getSubStatus() {
return wrapped_array<SUB_STATUS,4>($self->SubStatus);
}
}
%ignore STATUS; // We've specified an alternative way of wrapping this
%include "status.h"
这基本上和我在这里的回答是一样的,不过我们没有修改头文件来使用wrapped_array
,而是用%ignore
告诉SWIG,我们会提供自己的STATUS
定义来让它包裹。(这样做是完全合法的,SWIG生成的包裹器仍然会使用来自status.h的真实定义)
我们在这个修改后的定义中加入了一个getSubStatus()
,它返回一个对象,这个对象就像是STATUS
中真实数组的代理。这个代理又提供了__getitem__
、__setitem__
和__len__
,这些是Python用来处理下标操作符所需要的。
可能有一种方法可以在Python中正确地做到这一点,而不需要getSubStatus()
,让SWIG适当地设置__swig_setmethods__["SubStatus"]
和__swig_getmethods__["SubStatus"]
,但我现在不太确定怎么让SWIG在Python中做到这一点。
如果你使用的是C,而不是C++,你可能想要放弃模板,直接使用一个普通的struct
,并用指针代替数组的引用。