2016-07-24 18 views
0

Swig docsと@FlexoによるSWIG in typemap works, but argout does notの素晴らしい説明によると、argoutのtypemapは参照引数をPythonの戻り値に変換します。SWIG/Pythonでの引数の返信

私はdictを渡し、次にのunordered_mapに変換され、次にC++のlibに読み込まれるシナリオがあります。コードを進めていくうちに、C++から返された後にマッピングが変更されたことがわかります。なぜunordered_mapdictに変換して渡す可能性がないのだろうかと思います。それとも今は可能なのですか?私は何かを見落としていますか?

ありがとうございます!

答えて

3

私はあなたが求めている正確に何のように少し混乱していますが、私の理解では、次のとおりです。

  • あなたは、いくつかの関数の引数のためのC++ unordered_mapにPythonのdictを変換するタイプマップ「に」を持っています。
  • この関数は、unordered_mapを変更します。
  • この機能が完了すると、Python dictが現在のunordered_mapに更新され、何らかの理由でこの手順に問題があります。
  • unordered_mapに変換する方法を知っているので、unordered_mapをPython C-APIを使用してdictに変換する方法を基本的には知っていると思われますが、コードを入れるためのSWIGのtypemapが不明です。

ので、これらの仮定の下で、私は助けしようとするでしょう:

  • "argoutのタイプマップは、Pythonでの戻り値に参照引数をオン"。これは主にこの目的のために使用されますが、実際はそうではありません。 "argout" typemapは、の後にラッパーコードに挿入される関数の引数(内部では$1と呼ばれます)を処理するためのコードを提供しています。これを、提供されたPython引数$inputをC++引数$1に変換するコードを提供する "in"タイプマップと比較してください。これは明らかに、C++関数が呼び出されるの前にラッパーコードに挿入されます。

  • 元(上記連結SWIGのドキュメントを参照)$inputとして「argout」タイプマップで言及、及び$1としてunordered_mapを変更することができるPythonのdict渡します。

  • したがって、既存の "in"タイプマップと同じ引数シグネチャの "argout"タイプマップを作成し、(Python C-APIを使用して)コードを挿入してPython dict$input)の内容は、unordered_map$1)の内容を反映しています。これは通常、新しいPythonのdictに戻す$1を変換し、あなたが$resultで参照することができPythonの戻りオブジェクトにこれを追加します「argout」タイプマップ、古典的な使用とは異なることを

  • 注意。

これが役立ちます。まだ何らかの点で立ち往生している場合は、質問を編集して問題のある箇所を明確にしてください。

+0

ありがとう、たくさんのm7thon! 2番目の最後の弾丸は私が行方不明だったものでした。提供されたSwigの例から、私はあなたの最後の弾丸が(戻り値を使って)データを返す唯一の方法だと考えました。 –

+1

@wr m7thonはこの答えにスポットが当たっています。あなたが気をつけて気をつけなければならないことの1つは、Python開発者(つまり、バインディングのユーザ)がその動作を期待していることです。理想的には、混乱を最小限に抑えたいと思っています。通常、Pythonでは入力引数を不変にするために、C++とは違って、constを介して(たとえば)/その動作が何であるかを参照しないで簡単に推論することができないためです。これはほとんどの場合、代わりにオプションとして値を返すことになります。これは、戻り値がうまく設計されたインターフェイスで成功/失敗を示すために使用されていないためです。 – Flexo

0

私はすでにユーザーが自分の問題を解決していることをよく知っていますが、ここでは解決策があります。入力辞書の非文字列値を避けるために、入力の検証が導入される場合があります。

ヘッダファイル

// File: test.h 
#pragma once 

#include <iostream> 
#include <string> 
#include <unordered_map> 

void method(std::unordered_map<std::string, std::string>* inout) { 

    for(const auto& n : (*inout)) { 
    std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n"; 
    } 

    (*inout)["BLACK"] = "#000000"; 
}; 

インタフェースファイル

// File : dictmap.i 
%module dictmap 

%{ 
    #include "test.h" 
%} 

%include "typemaps.i" 

%typemap(in) std::unordered_map<std::string, std::string>* (std::unordered_map<std::string, std::string> temp) { 

    PyObject *key, *value; 
    Py_ssize_t pos = 0; 

    $1 = &temp; 

    temp = std::unordered_map<std::string, std::string>(); 
    while (PyDict_Next($input, &pos, &key, &value)) { 
    (*$1)[PyString_AsString(key)] = std::string(PyString_AsString(value)); 
    } 
} 

%typemap(argout) std::unordered_map<std::string, std::string>* { 
$result = PyDict_New(); 
for(const auto& n : *$1) { 
    PyDict_SetItemString($result, n.first.c_str(), 
      PyString_FromString(n.second.c_str())); 
} 
} 
%include "test.h" 

テスト

import dictmap 
out = dictmap.method({'WHITE' : '#FFFFFF'}) 

出力で更新された辞書

In[2]: out 
Out[3] : {'BLACK': '#000000', 'WHITE': '#FFFFFF'} 
+0

python3を使って作業するとき、 'PyString_AsString'がヌルポインタを返すことに気付くかもしれません。 'PyString_AsString'の代わりに' PyUnicode_AsUTF8'を使う必要があるかもしれません。 –

関連する問題