SWIG Python到C++:设置类型为map<string, int>的结构成员时出现TypeError

3 投票
1 回答
1835 浏览
提问于 2025-04-17 10:59

SWIG似乎在生成将结构体字段类型为map的绑定时出现了问题,导致在尝试将map字段设置为Python字典时出现类型错误。我是不是漏掉了什么错误?是个不被支持的用法?还是SWIG本身的bug?

首先是输出结果

Traceback (most recent call last):
  File ".\use_test.py", line 4, in <module>
    struct.data = { 'A':1, 'B':2 }
  File "C:\Users\kmahan\Projects\SwigTest\test.py", line 150, in <lambda>
    __setattr__ = lambda self, name, value: _swig_setattr(self, MyStruct, name, value)
  File "C:\Users\kmahan\Projects\SwigTest\test.py", line 49, in _swig_setattr
    return _swig_setattr_nondynamic(self,class_type,name,value,0)
  File "C:\Users\kmahan\Projects\SwigTest\test.py", line 42, in _swig_setattr_nondynamic
    if method: return method(self,value)
TypeError: in method 'MyStruct_data_set', argument 2 of type 'std::map< std::string,unsigned int,std::less< std::string >,std::allocator< std::pair< std::string const,unsigned int > > > *'

这是我的测试案例:

test.i

%module test

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

namespace std {
    %template(StringIntMap) map<string, unsigned int>;
}

%{
#include "test.h"
%}

%include "test.h"

test.h

#ifndef _TEST_H_
#define _TEST_H_

#include <string>
#include <map>

struct MyStruct 
{
    std::map<std::string, unsigned int> data;
};

#endif //_TEST_H_

test.cpp

#include "test.h"

run_test.py

import test

struct = test.MyStruct()
struct.data = { 'A':1, 'B':2 }

print struct.data

我用命令swig -python -c++ -o test_wrapper.cpp test.i来构建test_wrapper.cpp,编译其他所有文件,然后运行run_test.py。

作为一种变通办法,我可以明确地定义一个设置函数(void setData(const map<string, unsigned int>& data)),这会生成不同的转换代码——它通过traits_asptr而不是SWIG_ConvertPtr来处理——看起来可以工作,但不太符合Python的风格!

编辑

这是我的.i文件,它将属性的获取和设置通过C++的getter和setter进行处理。我觉得这就是Nathan在他回答下方评论中提到的建议。

%module test

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

namespace std {
    %template(StringIntMap) map<string, unsigned int>;
}

struct MyStruct 
{
    const std::map<std::string, unsigned int>& getData() const;
    void setData(const std::map<std::string, unsigned int>&);

    %pythoncode %{
        __swig_getmethods__["data"] = getData
        __swig_setmethods__["data"] = setData
        if _newclass:
            data = _swig_property(getData, setData)
    %}
};

1 个回答

1

当你在设置 struct.data 时,它其实是希望你给它一个 test.StringIntMap,而不是一个 Python 的 dict

最简单的方法就是这样做:

struct.data = test.StringIntMap({ 'A':1, 'B':2 })

撰写回答