swig/python:对象不支持索引

2024-05-18 20:04:55 发布

您现在位置:Python中文网/ 问答频道 /正文

给定这组文件:

食品卫生:

#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]; }
};

在食品.cpp公司名称:

^{pr2}$

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]; }
}

在设置.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"],
      )

在测试.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

但当我想逃跑的时候测试.py我会得到:

TypeError: 'foo.intFoo' object does not support indexing

foo.i中的extend语句是在任何其他相关线程上建议的答案,这意味着我在这里使用它不正确。有人能解释一下如何解决这个问题,这样当我运行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


Tags: pyimportidreturnfooincludetemplatecpp
2条回答

(在这个例子中,我使用的是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添加的方法实际上并不是要添加它们的类的成员。要在这个上下文中访问m,我们需要用$self->m来引用它。SWIG将replace ^{}为我们提供适当的变量。(有必要快速浏览一下生成的代码,以了解其工作原理)

在调试类型映射或扩展时,一个有用的提示是搜索您在SWIG生成的输出中编写的代码—如果没有,那么它就不会按照您的想法应用。在

因此,一旦我们修复了m未声明的错误,我们将遇到另一个问题,因为您使用-builtin进行了编译:

^{pr2}$

即使您添加了__getitem__,但是使用f[n]建立索引仍然不起作用。这是因为在Python中使用纯C-API类时,操作符重载的工作方式并不相同。您已经成功地添加了一个__getitem__方法,但是Python正在builtin type's slots(特别是mp_下标)中寻找执行该操作的方法。所以我们也需要解决这个问题。完成后,我看起来像:

%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[]

最后,您可能希望将返回类型改为const T0&,或者更好地为非常数整型引用编写一个Python类型到代理对象。在

我已经将错误的答案(声明%extent只能在没有-builtin选项的情况下使用)改为有效的方法,但同样是没有“内置”选项

在设置.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"],
      )

福。我

^{pr2}$

请注意,扩展是如何生成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:

相关问题 更多 >

    热门问题