当前位置: 首页 > 知识库问答 >
问题:

如何在Python中为类类型应用SWIG输出类型映射?

许博达
2023-03-14

我在使用SWIG(3.0.6版)围绕C库生成Python包装时遇到了一些问题。

我的问题与应用输出类型映射有关,特别是在类类型的指针/引用的情况下。

为了说明,这就是我想要的标准类型,它是有效的:

// .h
int add(const long arg1,const long arg2,long& resultLong);

// interface.i
%apply long& OUTPUT { long& resultLong };
int add(const long arg1,const long arg2,long& resultLong);

// projectWrapper.py
def add(arg1, arg2):
    return _projectWrapper.add(arg1, arg2)
addTerm = _projectWrapper.add

// usage
>>> result = projectWrapper.add(2, 4)
>>> print result
[0, 6L]

您不必传入“resultLong”,但它会自动附加到结果中。太棒了

但是,当输出类型是指向类类型的指针时,这似乎不像我期望的那样工作:

// .h
int GetClassType(const char* name, exportedClassType*& resultPointer);

class exportedClassType
{...}

// interface.i
%apply exportedClassType*& OUTPUT { exportedClassType*& resultPointer };    
int GetClassType(const char* name, exportedClassType*& resultPointer);

// projectWrapper.py
def GetClassType(name, resultPointer):
    return _projectWrapper.GetClassType(name, resultPointer)
GetClassType = _projectWrapper.GetClassType

问题似乎是SWIG没有以与简单类型相同的方式处理它。它仍然在包装函数签名中显示为“输入”参数。

// attempted usage
>>> classType = projectWrapper.GetClassType("name")
TypeError: GetClassType() takes exactly 2 arguments (1 given)

>>> result = 0
>>> projectWrapper.GetClassType("name", result)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: in method 'GetClassType', argument 2 of type 'exportedClassType *&'

有人能告诉我我做错了什么吗?或者给我指出正确的方向?任何帮助,谢谢!谢谢

共有3个答案

卫博雅
2023-03-14

我认为你需要使用指针。我也不确定在混合打印图和返回语句时会发生什么。一个最小的示例文件tst。我

%module tst

%{

  // declaration:
  void add(long *resultLong, const long arg1,const long arg2);
  long mul(const long a, const long b);

  // the code:
  void add(long *resultLong, const long arg1,const long arg2) {
    *resultLong = arg1 + arg2;
  }
  long mul(const long a, const long b) {
    return a*b;
  }

%}

// The wrapper:
%apply (long* OUTPUT) { long* resultLong }; 
void add(long* resultLong, const long arg1,const long arg2);
long mul(const long a, const long b);

翻译后(我总是使用CMake),python中的用法是:

import tst
x = tst.add(3, 4)  # results in 7L    
y = tst.mul(3, 4)  # results in 12L

我认为对标量数据类型使用返回语句而不是类型图更好。在接口数组时,我建议使用numpy. i的预定义类型图。

池麒
2023-03-14

这不是一个答案,只是没有足够的声誉评论:(

因为你需要在C中使用指针,而Python没有指针(所以你无论如何都不能对Python中的当前“结果”做任何事情)。

您能否按照@Jens Munk的建议添加包装器以将指针隐藏到. h中:

class exportedClassType_ptr {
public:
    exportedClassType* ptr;
    exportedClassType_ptr( exportedClassType& input ) {
        this->ptr = &input;
    }
};

int GetClassType( const char* name, exportedClassType_ptr& resultPointer ) {
    return GetClassType( name, resultPointer.ptr );
}

修改我要调用新方法的文件:

%apply exportedClassType_ptr& OUTPUT { exportedClassType_ptr& resultPointer };    
int GetClassType( const char* name, exportedClassType_ptr& resultPointer );

在Python中编写如下内容:

>>> realResult = projectWrapper.exportedClassType()
>>> result = projectWrapper.exportedClassType_ptr(realResult)
>>> projectWrapper.GetClassType("name", result)

并在未来的工作中使用“realResult”。

农波涛
2023-03-14

这个问题已经有一段时间没有解决了,所以我想我最好为这个问题提供一个解决方案。OUTPUT typemap仅适用于简单类型,因此通过组合中的argouttypemap给出了解决方案。

考虑这种情况,我们有一个C类SampleImpl实现一个C接口SampleBase,从技术上讲,它不是一个接口,因为它涉及一个虚拟析构函数的实现。假设我们有一个静态函数,它返回一个错误代码和接口的一个实现。后者作为指针的引用,这就是上述情况。

接口头:

// Sample.hpp
#pragma once
namespace Module {
  class SampleBase {
  public:
#ifndef SWIG
    // Hint to the programmer to implement this function
    static int SampleCreate(SampleBase *&obj);
#endif
    virtual ~SampleBase() = default;
  };
}

实现标题:

// Sample_impl.hpp
#pragma once
#include "Sample.hpp"

namespace Module {
  class SampleImpl : public SampleBase {
  public:
    static int SampleCreate(Module::SampleBase *&obj);

    SampleImpl();
    virtual ~SampleImpl();
  private:
    float a;
  };
}

实施:

// Sample_impl.cpp
#include "Sample_impl.hpp"
#include <cstdio>

namespace Module {
  int SampleImpl::SampleCreate(Module::SampleBase*& obj) {
    obj = (SampleBase*) new SampleImpl();
    return 0;
  }
  SampleImpl::SampleImpl() {
    printf("SampleImpl::SampleImpl()\n");
  }

  SampleImpl::~SampleImpl() {
    printf("SampleImpl::~SampleImpl()\n");
  }
}

SWIG接口(使用argout类型映射)

// example.i
%module example
%{
  #define SWIG_FILE_WITH_INIT
  #include "Sample.hpp"
  #include "Sample_impl.hpp"
%}

%include "typemaps.i"

%typemap(in, numinputs=0) Module::SampleBase *&obj (Module::SampleBase *temp) {
  $1 = &temp;
}

%typemap(argout) Module::SampleBase *& {
  PyObject* temp = NULL;
  if (!PyList_Check($result)) {
    temp = $result;
    $result = PyList_New(1);
    PyList_SetItem($result, 0, temp);

    // Create shadow object (do not use SWIG_POINTER_NEW)
    temp = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
             $descriptor(Module::SampleBase*),
             SWIG_POINTER_OWN | 0);

    PyList_Append($result, temp);
    Py_DECREF(temp);
  }
}

Python中的用法

import example

// Creating specialization
obj = example.SampleImpl()
del obj

// Creation of object using output typemap
errorCode, obj = example.SampleImpl_SampleCreate()
del obj

 类似资料:
  • 我在目标语言为python的swig接口文件中成功地使用了以下类型映射: 然而,当我将目标语言更改为java时,当我尝试构建swg生成的自动生成的c包装代码时,我会遇到很多编译时错误,即。 等等... 我注意到,在python案例中,粘贴到swig包装器代码中的代码包含,等声明,这些代码来自 它位于 当目标语言为java时,此等效代码不会粘贴到swig包装器代码中。我不完全确定为什么不会发生这种情

  • 我正在使用泛型在python中创建一个List类(类似于java列表的列表)。类节点也是通用的,我正在为上一个和下一个节点创建 getter 和 setters 方法。我想知道如何返回像类节点本身这样的类型?这是我的进步: 我试过 但它给了我错误

  • 我在尝试使用JSON_serializable序列化从internet获取的复杂JSON并使用FutureProvider将它们连接在一起时遇到了这个问题。这是json文件, 这是包含序列化类的代码, 获取json文件并将其转换为dart的未来提供者, 这是基因编码, 这是转换后的json文件显示的代码 当我试着运行这个项目时,我遇到了这个错误 i/flutter(23347): type'Lis

  • 我有大约40个API,它们具有类似的基本响应结构,如下所示: 因此,我有一个基本响应类,采用T类型的泛型,如下所示: 因此,对于API A,它返回类型为的对象及其自己的字段,我将返回响应作为控制器中的API响应: 在控制器中:响应数据=新响应();ResponseEntity response=新的ResponseEntity 在swagger中有没有一种方法可以递归地指定响应对象的模型?例如,我

  • 我正在尝试有一个通量通用转换器使用通用类型在Java 8。我把我的代码建立在这个答案的基础上。其思想基本上是实现这个特定的转换器->: 类型转换器->转换为我想要的任何类型。因此,我正在使用构造函数创建一个类型为的类,并返回一个方法。我想在调用上创建类似这样的多个条目:,但类类型不同。但它甚至对整数也不起作用。 当我使用此单元测试进行测试时,我得到错误:。

  • 类型映射 web3j中使用的原生Java到ABI类型映射如下: boolean -> bool BigInteger -> uint/int byte[] -> bytes String -> string and address types List<> -> dynamic/static array BigInteger类型必须用于数字类型,因为Ethereum以太坊中的数字类型是256位整数