鉴于这组文件:
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(Attempt1):
%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])
我构建了扩展程序:
python setup.py build_ext --force -i
但是当我尝试运行test.py时,我会得到:
TypeError: 'foo.intFoo' object does not support indexing
extend
中的语句foo.i
是在任何其他SO相关主题上建议的答案,这意味着我在这里错误地使用它。任何人都可以解释如何解决这个问题,这样当我运行test.py
时能够成功使用[]
运算符吗?
另一种尝试:
ATTEMPT2:
%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
Attempt3
%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
答案 0 :(得分:7)
(在这个例子中,我正在使用你的第一个版本的foo.i)
首先需要在%extend
指令之前指定%template
才能生效。
修复后,我们现在从%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
添加的方法实际上并不是您要添加它们的类的成员。要在此上下文中访问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类操作符重载不能以相同的方式工作。您已成功添加__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__
,因为该功能已在插槽中注册,因此应该可以在没有operator[]
的情况下调用%extend
例如)
最后,您可能希望将返回类型更改为const T0&
,或者将Python类型编写为代理对象,以便更好地进行非const int引用。
答案 1 :(得分:3)
我更改了错误的答案(说%extent
只能在没有-builtin
选项的情况下使用)才能使用有效的内容,但只有在没有内置&#39;选项
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内置类型
当使用-builtin时,将剥离纯python层。每 wrapped类被转换为一个继承的新的python内置类型 从SwigPyObject,直接返回SwigPyObject实例 从包装的方法。有关python内置的更多信息 扩展,请参阅python文档: