python - SWIG 将 map vector 转换为 python 字典列表

标签 python c++ swig typemaps

嗨,我正在努力使用 SWIG 包装 C++ 以在 python 中使用。为了包装 C++ 类,我使用 SWIG。我对类型映射不太了解,因此我陷入了困境。我有一个由多个 map 组成的 vector ,即。 std::vector> 我想从 C++ 函数返回它并将其转换为 python 中的 dict 列表。我在网上搜索但找不到任何东西。

我有一堂这样的课:

std::vector<std::map<std::string, int>> WapperCode::wrapper_fuc(){
std::vector<std::map<std::string, int>> outer_vector;
for(int i = 0 ; i < 10 ; i++){
    std::map<std::string, int> inner_dict;
    inner_dict.insert(std::pair<std::string, int>("first", 1));
    inner_dict.insert(std::pair<std::string, int>("second", 2));
    inner_dict.insert(std::pair<std::string, int>("third", 3));
    outer_vector.insert(outer_vector.begin() + i, inner_dict);
}
return outer_vector;}

我的界面文件包含这个


%module wrapper
%{
#include "wrapper.h"
#include <cstdio>
#include <cstdlib>
#include <sys/stat.h>
#include <map> 
#include <vector>
#define SWIG_PYTHON_STRICT_BYTE_CHAR // Swig is giving const char while wrapping bytes.
%}

%include "std_vector.i"
%include "std_map.i"
%include "std_pair.i"
%include "std_wstring.i" // Use this for abby wchar dependency
%include "std_string.i" // Get C++ string
%include "./lib/wrapper.h"


%typemap(out) std::vector< std::map< std::string,int,std::less< std::string >,std::allocator< std::pair< std::string const,int > > >,std::allocator< std::map< std::string,int,std::less< std::string >,std::allocator< std::pair< std::string const,int > > > > > & 
{
    for(int i = 0; i < $1->size(); ++i)
    {       
        int subLength = $1->data()[i].size();
        npy_intp dims[] = { subLength };
        PyObject* temp = PyArray_SimpleNewFromData(1, dims, NPY_INT, $1->data()[i].data());
        $result = SWIG_Python_AppendOutput($result, temp);
    }       
}

但是当我从 python 调用这个模块时,我得到了这个:

Out[3]: <Swig Object of type 'std::vector< std::map< std::string,int,std::less< std::string >,std::allocator< std::pair< std::string const,int > > >,std::allocator< std::map< std::string,int,std::less< std::string >,std::allocator< std::pair< std::string const,int > > > > > *' at 0x7f4025d8e810>

最佳答案

如果您希望返回值是 Python 字典的实际 Python 列表,则确实需要类型映射,但包含的预定义模板可能适合您。这是一个例子:

测试.i:

%module test

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

std::vector<std::map<std::string, int>> func() {
    std::vector<std::map<std::string, int>> outer_vector;
    for(int i = 0 ; i < 10 ; i++){
        std::map<std::string, int> inner_dict;
        inner_dict.insert(std::pair<std::string, int>("first", 1));
        inner_dict.insert(std::pair<std::string, int>("second", 2));
        inner_dict.insert(std::pair<std::string, int>("third", 3));
        outer_vector.insert(outer_vector.begin() + i, inner_dict);
    }
    return outer_vector;
}
%}

// These declare the templates
%include <std_vector.i>
%include <std_map.i>
%include <std_string.i>

// You must declare the template instances used so SWIG builds wrappers for them.
// Declare the inner templates before the outer ones.
%template(SiMap) std::map<std::string,int>;
%template(VectorSiMap) std::vector<std::map<std::string,int>>;

// Tell SWIG to wrap the function.
std::vector<std::map<std::string, int>> func();

用例:

>>> import test
>>> d=test.func()
>>> len(d)
10
>>> d
(<test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA68E0B10> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA712A570> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA692A750> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA7110750> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA7110480> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA71105A0> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA71107E0> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA7110840> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA7110900> >, <test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA71109F0> >)

它看起来不太漂亮,但可以通过以下方式转换为 Python 列表/字典:

>>> [dict(x) for x in d]
[{'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}, {'first': 1, 'second': 2, 'third': 3}]

它仍然可以像列表或字典一样访问,即使没有像上面那样转换为很好地打印:

>>> d[0]
<test.SiMap; proxy of <Swig Object of type 'std::map< std::string,int > *' at 0x0000028EA68E0B10> >
>>> d[0]['first']
1
>>> d[1]['second']
2

模板中使用的名称也可用于构建传递给 C++ 代码的对象:

>>> m = test.SiMap()
>>> m['first'] = 2
>>> v = test.VectorSiMap()
>>> v.push_back(m)
>>> v
<test.VectorSiMap; proxy of <Swig Object of type 'std::vector< std::map< std::string,int,std::less< std::string >,std::allocator< std::pair< std::string const,int > > > > *' at 0x0000028EA71381E0> >
>>> [dict(x) for x in v]
[{'first': 2}]

关于python - SWIG 将 map vector 转换为 python 字典列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63705552/

相关文章:

c++ - 如何创建模板化类对象数组?

python - 如何重新触发之前的 'while' 循环

python - 从网站读取 .tar.gz 文件的内容到 python 3.x 对象中

python - 检查 ISBN 书号是否有效 Python

python - PocketSphinx 安装找不到 swig.exe

java - 如何在 SWIG Java 目标中包装对枚举的所有引用?

c# - 为包含 void* 参数的函数创建 SWIG C# 包装器

python - 从宽到长返回空输出 - Python 数据框

c++ - decltype 和成员函数(非指针)类型

c++ - 到 bool 的转换是如何进行的?