SWIG如何在Python中包装map<string,string>?
我正在使用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 &""'");
}
很明显,它知道这个参数存在,并且应该是某种可以转换为map的东西。但我就是搞不清楚到底应该传什么进去。
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