SWIG如何在Python中包装一个map<string,string>?

13
我正在使用SWIG 2.0创建一个C++库的Python包装器。其中一个方法有一个 "const std::map&" 类型的参数。SWIG愉快地为它生成了一个包装器,但我无法弄清楚如何调用这个方法。如果我传递例如{"a":"b"}作为该参数,我会收到"NotImplementedError: Wrong number or type of arguments for overloaded function" 错误。
我查看了生成的.cxx文件,希望它能澄清问题,但它没有。以下是处理该参数的代码:
res4 = SWIG_ConvertPtr(obj3, &argp4, SWIGTYPE_p_std__mapT_std__string_std__string_t,  0  | 0);
if (!SWIG_IsOK(res4)) {
  SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "new_Context" "', argument " "4"" of type '" "std::map< std::string,std::string > const &""'"); 
}

它明确知道该参数存在,而且应该是一些需要转换为映射的东西。但我不知道它实际上希望我传递什么。


1
在你的swig文件中,你是否明确地包装了map?我认为你需要在Python代码中调用insert来创建一个类型变量。 - mark
1个回答

24

当你在使用C++模板时(例如std::map<string, string>),你需要在你的.i文件中为它创建一个别名,这样你才能在python中使用它:

namespace std {
%template(map_string_string) map<string, string>;
}

现在假设你想要包装一个看起来像这样的函数:

void foo(const std::map<string, string> &arg);

在Python端,你需要把一个map_string_string传递给foo,而不是一个Python字典。不过你可以通过以下方式将Python字典轻松转换为map:

map_string_string({ 'a' : 'b' })

所以如果你想调用foo,你需要这样做:

foo(map_string_string({ 'a' : 'b' }))

这是一个完整的示例代码,可以正常运行。

// test.i
%module test

%include "std_string.i"
%include "std_map.i"

namespace std {
    %template(map_string_string) map<string, string>;
}

void foo(const std::map<std::string, std::string> &val);

%{
#include <iostream>
#include <string>
#include <map>

using namespace std;
void
foo(const map<string, string> &val)
{
    map<string, string>::const_iterator i = val.begin();
    map<string, string>::const_iterator end = val.end();
    while (i != end) {
        cout << i->first << " : " << i->second << endl;
        ++i;
    }
}

%}

以下是 Python 测试代码:

#run_test.py
import test

x = test.map_string_string({ 'a' : 'b', 'c' : 'd' })
test.foo(x)

我的命令行是:

% swig -python -c++ test.i
% g++ -fPIC -shared -I/usr/include/python2.7  -o _test.so test_wrap.cxx
% python run_test.py
a : b
c : d

7
看起来你甚至不需要在Python代码中使用map_string_string类型。一旦声明了该模板,SWIG可以自动找出如何将字典转换为它。 - peastman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接