如何在Python中对类类型应用SWIG OUTPUT类型映射? [英] How to apply SWIG OUTPUT typemaps for class types in Python?

查看:191
本文介绍了如何在Python中对类类型应用SWIG OUTPUT类型映射?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用SWIG(版本3.0.6)创建一个C ++库的Python包装器时遇到了一些麻烦。



我的问题涉及应用OUTPUT类型对于类类型的指针/引用。



为了说明,这是我想要的标准类型,它的工作原理:

  // .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

//用法
>>> result = projectWrapper.add(2,4)
>>>>打印结果
[0,6L]

您不必传入resultLong ,但会自动附加到结果。非常好!



但是,当输出类型是类类型的一些指针时,这看起来并不能正常工作:

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

class exportsClassType
{...}

// 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没有像简单类型一样处理它。它仍然在包装函数签名中显示为输入参数。

  //尝试使用
> ;> classType = projectWrapper.GetClassType(name)
TypeError:GetClassType()正好有2个参数(给定1个)

> result = 0
>>>> projectWrapper.GetClassType(name,result)
回溯(最近一次调用)
在< module>中的文件< input&
TypeError:在方法'GetClassType'中,类型为'exportedClassType *&'的参数2

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

解决方案

这个问题显示为未解决一段时间,所以我想我最好提供一个问题的解决方案。 OUTPUT类型只适用于简单类型,所以通过组合 in argout typemap来给出一个解决方案。 / p>

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



界面标题:

  // Sample.hpp 
#pragma once
命名空间模块{
class SampleBase {
public:
#ifndef SWIG
//提示程序员实现此函数
static int SampleCreate(SampleBase *& obj);
#endif
virtual〜SampleBase()= default;
};
}

实施标题:

  // Sample_impl.hpp 
#pragma once
#includeSample.hpp

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

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

实施:

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

命名空间模块{
int SampleImpl :: SampleCreate(Module :: SampleBase *& obj){
obj =(SampleBase *)new SampleImpl
return 0;
}
SampleImpl :: SampleImpl(){
printf(SampleImpl :: SampleImpl()\\\
);
}

SampleImpl ::〜SampleImpl(){
printf(SampleImpl ::〜SampleImpl()\\\
);
}
}

SWIG界面(使用argout typemap)

  // example.i 
%模块示例
%{
#define SWIG_FILE_WITH_INIT
# includeSample.hpp
#includeSample_impl.hpp
%}

%includetypemaps.i

%typemap ,numinputs = 0)模块:: 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);

//创建shadow对象(不使用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 

//创建专业化
obj = example.SampleImpl()
del obj

//使用输出typemap创建对象
errorCode,obj = example.SampleImpl_SampleCreate()
del obj


I am having some trouble generating a Python wrapper around a C++ library using SWIG (version 3.0.6).

My issue relates to applying the OUTPUT typemap, specifically in the case of pointers/references to class types.

To illustrate, this is what I want for standard types, and it works:

// .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]

You don't have to pass in "resultLong", but it is appended to the result automatically. Great!

However, this doesn't seem to be working as I expect when the output type is some pointer to a class type:

// .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

The problem seems to be that SWIG has not processed it in the same way as the simple type. It still appears as an "input" parameter in the wrapped function signature.

// 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 *&'

Can somebody please tell me what I'm doing wrong or point me in the right direction? Any help gratefully received! Thanks

解决方案

This question has appeared as unresolved for quite some time, so I thought that I better provide a solution to the question. The OUTPUT typemap only applies to simple types, so a solution is given by combining an in and an argout typemap.

Consider the situation, where we have a C++ class SampleImpl implementing a C++ interface SampleBase, which is technically not an interface, since it involves the implementation of a virtual destructor. Suppose we have a static function, which returns an error code and an implementation of the interface. The latter as a reference to a pointer, which is the situation above.

Interface header:

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

Implementation header:

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

Implementation:

// 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 interface (using argout typemap)

// 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);
  }
}

Usage in 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 OUTPUT类型映射?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆