swig/python: 对象不支持索引
swig/python: object does not support indexing
给定这组文件:
foo.h:
#pragma once
#include <stdio.h>
template <class T0> class Foo {
public:
T0 m[3];
Foo(const T0 &a, const T0 &b, const T0 &c) {
m[0] = a;
m[1] = b;
m[2] = c;
}
void info() { printf("%d %d %d\n", m[0], m[1], m[2]); }
// T0 &operator[](int id) { return ((T0 *)m)[id]; }
};
foo.cpp:
#include "foo.h"
foo.i(尝试 1):
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%template(intFoo) Foo<int>;
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
setup.py:
import os
import sys
from setuptools import setup, Extension
foo_module = Extension('_foo',
sources=[
'foo.i',
'foo.cpp'
],
swig_opts=['-c++', '-py3', '-builtin'],
include_dirs=['.']
)
setup(name='foo',
version='0.1',
platforms=['Windows', 'Linux'],
ext_modules=[foo_module],
py_modules=["foo"],
)
test.py:
from foo import intFoo
a = intFoo(10,20,30)
print(dir(a))
a.info()
print(a[2])
我构建扩展 运行ning:
python setup.py build_ext --force -i
但是当我尝试 运行 test.py 我会得到:
TypeError: 'foo.intFoo' object does not support indexing
foo.i
中的语句 extend
是在任何其他 SO 相关线程上建议的答案,这意味着我在这里使用不正确。谁能解释一下如何解决这个问题,以便当我 运行 test.py
能够成功使用 []
运算符时?
另一次尝试:
尝试 2:
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%template(intFoo) Foo<int>;
%extend intFoo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
抛出这个错误TypeError: 'foo.intFoo' object does not support indexing
尝试 3
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
%template(intFoo) Foo<int>;
抛出这个错误foo_wrap.cpp(3808): error C2065: 'm': undeclared identifier
我已将错误的答案(指出 %extent
只能在没有 -builtin
选项的情况下使用)更改为有效的答案,但同样只能在没有 'built-in' 选项的情况下使用
setup.py
import os
import sys
from setuptools import setup, Extension
foo_module = Extension('_foo',
sources=[
'foo.i', 'foo.cpp'
],
swig_opts=['-c++'],
include_dirs=['.']
)
setup(name='foo',
version='0.1',
platforms=['Windows', 'Linux'],
ext_modules=[foo_module],
py_modules=["foo"],
)
foo.i
%module foo
%{
#include "foo.h"
%}
%include "carrays.i"
%array_functions(int, intArray);
%include "foo.h"
%extend Foo<int> {
%pythoncode %{
def __getitem__(self, id):
return _foo.intArray_getitem(self.m,id)
%}
};
%template(intFoo) Foo<int>;
请注意,扩展程序如何生成 Python
代码,让您可以做很多复杂的事情。
旧答案:
根据 SWIG 文档,python 层被剥离,因此 %extend
功能被忽略(这是不正确的,未创建代理对象)
参见 http://www.swig.org/Doc3.0/SWIGDocumentation.html
36.4.2 Built-in Types
When -builtin is used, the pure python layer is stripped off. Each
wrapped class is turned into a new python built-in type which inherits
from SwigPyObject, and SwigPyObject instances are returned directly
from the wrapped methods. For more information about python built-in
extensions, please refer to the python documentation:
(在整个示例中,我使用的是您的 foo.i 的第一个版本)
首先,您需要在 %template
指令之前指定 %extend
才能生效。
修复后,我们现在从您的 %extend
代码中得到一个编译器错误:
foo_wrap.cpp: In function 'int& Foo_Sl_int_Sg____getitem__(Foo<int>*, int)':
foo_wrap.cpp:3705:85: error: 'm' was not declared in this scope
发生这种情况是因为您使用 %extend
添加的方法并不是您要将它们添加到的 class 的真正成员。要在此上下文中访问 m
,我们需要使用 $self->m
来引用它。 SWIG 将为我们 replace $self
提供适当的变量。 (值得快速浏览一下生成的代码以了解其工作原理)
调试类型映射或扩展时的一个有用提示是搜索您在 SWIG 生成的输出中编写的代码 - 如果它不存在,则它没有按照您的想法应用。
因此,一旦我们修复了关于 m
未被声明的错误,我们就会遇到另一个问题,因为您使用 -builtin
:
进行了编译
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-e71eec16918d> in <module>()
----> 1 f[0]
TypeError: 'intFoo' object does not support indexing
In [4]: f.__getitem__(0)
Out[4]: <Swig Object of type 'int *' at 0xa8807d40>
即使您添加了 __getitem__
,使用 f[n]
建立索引仍然无效。发生这种情况是因为在 Python 运算符重载中使用纯 C-API classes 的工作方式不同。您已成功添加 __getitem__
方法,但 Python 正在 builtin type's slots(特别是 mp_subscript)中寻找执行操作的方法。所以我们也需要解决这个问题。完成后,工作 foo.i 看起来像:
%module foo
%{
#include "foo.h"
%}
%feature("python:slot", "mp_subscript", functype="binaryfunc") Foo::__getitem__;
%include "foo.h"
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)$self->m)[id]; }
}
%template(intFoo) Foo<int>;
所以现在我们可以做你想做的事了:
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
Out[3]: <Swig Object of type 'int *' at 0xb4024100>
(您实际上不必再调用它 __getitem__
,因为该函数已在插槽中注册,应该可以在没有 %extend
的情况下调用 operator[]
例如)
最后你可能想将 return 类型更改为 const T0&
,或者将 Python 类型写入代理对象以更好地引用非 const int。
给定这组文件:
foo.h:
#pragma once
#include <stdio.h>
template <class T0> class Foo {
public:
T0 m[3];
Foo(const T0 &a, const T0 &b, const T0 &c) {
m[0] = a;
m[1] = b;
m[2] = c;
}
void info() { printf("%d %d %d\n", m[0], m[1], m[2]); }
// T0 &operator[](int id) { return ((T0 *)m)[id]; }
};
foo.cpp:
#include "foo.h"
foo.i(尝试 1):
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%template(intFoo) Foo<int>;
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
setup.py:
import os
import sys
from setuptools import setup, Extension
foo_module = Extension('_foo',
sources=[
'foo.i',
'foo.cpp'
],
swig_opts=['-c++', '-py3', '-builtin'],
include_dirs=['.']
)
setup(name='foo',
version='0.1',
platforms=['Windows', 'Linux'],
ext_modules=[foo_module],
py_modules=["foo"],
)
test.py:
from foo import intFoo
a = intFoo(10,20,30)
print(dir(a))
a.info()
print(a[2])
我构建扩展 运行ning:
python setup.py build_ext --force -i
但是当我尝试 运行 test.py 我会得到:
TypeError: 'foo.intFoo' object does not support indexing
foo.i
中的语句 extend
是在任何其他 SO 相关线程上建议的答案,这意味着我在这里使用不正确。谁能解释一下如何解决这个问题,以便当我 运行 test.py
能够成功使用 []
运算符时?
另一次尝试:
尝试 2:
%module foo %{ #include "foo.h" %} %include "foo.h" %template(intFoo) Foo<int>; %extend intFoo{ T0& __getitem__(int id) { return ((T0 *)m)[id]; } }
抛出这个错误
TypeError: 'foo.intFoo' object does not support indexing
尝试 3
%module foo %{ #include "foo.h" %} %include "foo.h" %extend Foo{ T0& __getitem__(int id) { return ((T0 *)m)[id]; } } %template(intFoo) Foo<int>;
抛出这个错误
foo_wrap.cpp(3808): error C2065: 'm': undeclared identifier
我已将错误的答案(指出 %extent
只能在没有 -builtin
选项的情况下使用)更改为有效的答案,但同样只能在没有 'built-in' 选项的情况下使用
setup.py
import os
import sys
from setuptools import setup, Extension
foo_module = Extension('_foo',
sources=[
'foo.i', 'foo.cpp'
],
swig_opts=['-c++'],
include_dirs=['.']
)
setup(name='foo',
version='0.1',
platforms=['Windows', 'Linux'],
ext_modules=[foo_module],
py_modules=["foo"],
)
foo.i
%module foo
%{
#include "foo.h"
%}
%include "carrays.i"
%array_functions(int, intArray);
%include "foo.h"
%extend Foo<int> {
%pythoncode %{
def __getitem__(self, id):
return _foo.intArray_getitem(self.m,id)
%}
};
%template(intFoo) Foo<int>;
请注意,扩展程序如何生成 Python
代码,让您可以做很多复杂的事情。
旧答案:
根据 SWIG 文档,python 层被剥离,因此 %extend
功能被忽略(这是不正确的,未创建代理对象)
参见 http://www.swig.org/Doc3.0/SWIGDocumentation.html
36.4.2 Built-in Types
When -builtin is used, the pure python layer is stripped off. Each wrapped class is turned into a new python built-in type which inherits from SwigPyObject, and SwigPyObject instances are returned directly from the wrapped methods. For more information about python built-in extensions, please refer to the python documentation:
(在整个示例中,我使用的是您的 foo.i 的第一个版本)
首先,您需要在 %template
指令之前指定 %extend
才能生效。
修复后,我们现在从您的 %extend
代码中得到一个编译器错误:
foo_wrap.cpp: In function 'int& Foo_Sl_int_Sg____getitem__(Foo<int>*, int)':
foo_wrap.cpp:3705:85: error: 'm' was not declared in this scope
发生这种情况是因为您使用 %extend
添加的方法并不是您要将它们添加到的 class 的真正成员。要在此上下文中访问 m
,我们需要使用 $self->m
来引用它。 SWIG 将为我们 replace $self
提供适当的变量。 (值得快速浏览一下生成的代码以了解其工作原理)
调试类型映射或扩展时的一个有用提示是搜索您在 SWIG 生成的输出中编写的代码 - 如果它不存在,则它没有按照您的想法应用。
因此,一旦我们修复了关于 m
未被声明的错误,我们就会遇到另一个问题,因为您使用 -builtin
:
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-e71eec16918d> in <module>()
----> 1 f[0]
TypeError: 'intFoo' object does not support indexing
In [4]: f.__getitem__(0)
Out[4]: <Swig Object of type 'int *' at 0xa8807d40>
即使您添加了 __getitem__
,使用 f[n]
建立索引仍然无效。发生这种情况是因为在 Python 运算符重载中使用纯 C-API classes 的工作方式不同。您已成功添加 __getitem__
方法,但 Python 正在 builtin type's slots(特别是 mp_subscript)中寻找执行操作的方法。所以我们也需要解决这个问题。完成后,工作 foo.i 看起来像:
%module foo
%{
#include "foo.h"
%}
%feature("python:slot", "mp_subscript", functype="binaryfunc") Foo::__getitem__;
%include "foo.h"
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)$self->m)[id]; }
}
%template(intFoo) Foo<int>;
所以现在我们可以做你想做的事了:
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
Out[3]: <Swig Object of type 'int *' at 0xb4024100>
(您实际上不必再调用它 __getitem__
,因为该函数已在插槽中注册,应该可以在没有 %extend
的情况下调用 operator[]
例如)
最后你可能想将 return 类型更改为 const T0&
,或者将 Python 类型写入代理对象以更好地引用非 const int。