2015-09-09 13 views
10

Tôi đang gặp một số sự cố khi tạo trình bao bọc Python xung quanh thư viện C++ sử dụng SWIG (phiên bản 3.0.6).Làm thế nào để áp dụng các kiểu chữ SWIG OUTPUT cho các kiểu lớp trong Python?

Vấn đề của tôi liên quan đến việc áp dụng kiểu chữ OUTPUT, cụ thể trong trường hợp con trỏ/tham chiếu đến các loại lớp.

Để minh họa, đây là những gì tôi muốn với nhiều loại tiêu chuẩn, và nó hoạt động:

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

Bạn không cần phải vượt qua trong "resultLong", nhưng nó được nối vào kết quả tự động. Tuyệt quá!

Tuy nhiên, điều này dường như không được làm việc như tôi mong đợi khi các loại đầu ra là một số con trỏ tới một kiểu lớp:

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

Vấn đề dường như là SWIG đã không được xử lý nó trong cùng theo cách đơn giản. Nó vẫn xuất hiện như một tham số "đầu vào" trong chữ ký hàm bọc.

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

Ai đó có thể cho tôi biết tôi đang làm gì sai hoặc hướng tôi đi đúng hướng? Bất kỳ sự giúp đỡ biết ơn nhận được! Cảm ơn

+0

Bạn đã thử sử dụng con trỏ kép chưa? Tôi đã có vấn đề với con trỏ đôi và mã được tạo ra bằng cách sử dụng SWIG 2.0.7, nhưng điều này được giải quyết trong 3.X.X –

+0

Cảm ơn bạn đã trả lời. Xin lỗi, nó sẽ trông như thế nào trong file interface.i? – SWilliams

+0

Tôi nên đề cập rằng tôi không sở hữu C++ và không thể thay đổi chữ ký của phương thức ở đó. Tôi chắc chắn cần phải xử lý một phương thức lấy tham số 'exportsClassType * &'. – SWilliams

Trả lời

3

Câu hỏi này đã xuất hiện chưa được giải quyết trong một thời gian, vì vậy tôi nghĩ rằng tôi nên cung cấp giải pháp cho câu hỏi tốt hơn. Sơ đồ kiểu OUTPUT chỉ áp dụng cho các kiểu đơn giản, do đó, một giải pháp được đưa ra bằng cách kết hợp một in và một kiểu phông argout.

Hãy xem xét tình huống, nơi chúng tôi có lớp C++ SampleImpl triển khai giao diện C++ SampleBase, về mặt kỹ thuật không phải là giao diện vì nó liên quan đến việc triển khai trình phá hủy ảo. Giả sử chúng ta có một hàm tĩnh, hàm này trả về một mã lỗi và thực hiện giao diện. Cái sau là một tham chiếu đến một con trỏ, đó là tình huống trên.

tiêu đề Giao diện: tiêu đề

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

Thực hiện:

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

Thực hiện:

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

giao diện SWIG (sử dụng 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); 
    } 
} 

Cách sử dụng bằng Python

import example 

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

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

Điều này có vẻ như những gì tôi đang tìm kiếm, cảm ơn! – SWilliams

+0

Bạn được chào đón. Tôi đã thay đổi như vậy mà một đối tượng chỉ được thêm vào danh sách đầu ra nếu hàm tạo hoặc hàm trả về 0 vì không có lỗi. –

2

Nó không phải là một câu trả lời, chỉ là không đủ reputaiton cho một lời nhận xét :(

Vì em cần phải sử dụng con trỏ trong C++ và Python không có con trỏ (do đó bạn không thể làm bất cứ điều gì với hiện tại của bạn . 'kết quả' bằng Python anyway)

bạn có thể thêm giấy gói để che giấu con trỏ vào .h như đã được đề xuất bởi @Jens Munk:

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

sửa đổi tập tin .i để gọi phương thức mới:

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

bằng Python viết một cái gì đó như thế này:

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

và sử dụng 'realResult' cho công việc trong tương lai.

+0

Cảm ơn câu trả lời. Tôi thấy chính xác Jens Munk có ý gì khi bình luận của anh ấy. Tôi có một vấn đề với việc thực hiện điều này. Điều gì sẽ xảy ra nếu phương thức được bọc là một phương thức lớp, nói 'exportedClassType.GetClassType'? Làm thế nào tôi có thể tạo một phương thức ghi đè mới trên lớp mà sẽ có một 'exportedClasssType_ptr'? – SWilliams

+0

Thật khó để đưa ra một sugestion mà không có một ví dụ thực sự. Ví dụ bạn có thể tạo lớp dẫn xuất của riêng bạn 'class newClassWithoutPointers: public oldClassWithPointers {}' và thay đổi tất cả các phương thức với dữ liệu con trỏ đầu vào. Nhưng nó có thể hoạt động sai cách nếu tất cả các phương thức đó đang gọi 'new' hoặc' delete' cho con trỏ đầu vào. – embrio

+0

Điều này không hoàn toàn hoàn toàn cho trường hợp sử dụng của tôi (xem bình luận ở trên), nhưng đó là một ví dụ đầy đủ rõ ràng giải thích cách tiếp cận và khiến tôi không bị che khuất. Bạn nhận được tiền thưởng, cảm ơn một lần nữa. – SWilliams

0

Tôi nghĩ bạn cần sử dụng con trỏ. Tôi cũng không chắc chắn những gì sẽ xảy ra, khi trộn ra các bản đồ và báo cáo trả về. Một ví dụ nhỏ tập tin tst.i:

%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); 

Sau khi dịch (Tôi luôn luôn sử dụng CMake), việc sử dụng trong python sẽ là:

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

Tôi nghĩ rằng đó là tốt hơn sử dụng báo cáo lợi nhuận thay vì typemaps cho kiểu dữ liệu vô hướng . Khi interfacing mảng, tôi khuyên bạn nên sử dụng các bản đồ được xác định trước của numpy.i.

+0

Xin lỗi, tôi không thấy điều này áp dụng cho các loại lớp như được hỏi trong câu hỏi. – SWilliams

Các vấn đề liên quan