如何使用 SWIG 从 C++ 无序映射生成 Python 字典?
How to produce a Python dictionary from a C++ unordered map using SWIG?
我正在尝试使用 swig 将无序映射包装在 python 字典中:
// UsingAnUnorderedMap.h
#ifndef LEARNSWIG_USINGUNORDEREDMAP_H
#define LEARNSWIG_USINGUNORDEREDMAP_H
#include <unordered_map>
#include <string>
std::unordered_map<std::string, int> makeStringToIntMap(){
return std::unordered_map<std::string, int>{
{"first", 4},
{"second", 5},
};
}
#endif //LEARNSWIG_USINGUNORDEREDMAP_H
//UsingAnUnorderedMap.i
%module UsingUnorderedMap
%{
#include "UsingUnorderedMap.h"
#include <iostream>
#include <unordered_map>
%}
%include "std_string.i"
%include "std_pair.i"
%include "std_unordered_map.i"
%template(StringToIntMap) std::unordered_map<std::string,int>;
%include "UsingUnorderedMap.h"
%typemap(out) StringToIntMap {
PyDictObject* dict = PyDict_New($input);
for (auto &item: StringToIntMap){
PyDict_SetItem(dict, PyUnicode_FromString(item.first), item.second);
}
$result = dict;
}
# testUsingAnUnorderedMap.py
import sys
sys.path += [
r"D:\LearnSwig\install-msvc\UsingUnorderedMap"
]
import UsingUnorderedMap
print(type(UsingUnorderedMap.makeStringToIntMap()))
这会产生
<class 'UsingUnorderedMap.StringToIntMap'>
即它只是忽略了类型图。从技术上讲,StringToIntMap
的行为与 Python dict 几乎相同 - 据我所知,但我认为 Python 词典中的 Python 用户很舒服,所以它如果这是一本简单的字典会更好。有人对如何实现这一目标有任何指示吗?
为方便起见,您可以使用以下 CMake 代码构建此代码。请注意,我使用命令 -DSWIG_EXECUTABLE=/path/to/swig.exe
.
构建它
# CMakeLists.txt
set(Python_ROOT_DIR "C:/Miniconda3")
find_package(Python COMPONENTS Interpreter Development NumPy)
message("Python_EXECUTABLE ${Python_EXECUTABLE}")
find_package(SWIG 4.0.0 REQUIRED
COMPONENTS python
)
include(UseSWIG)
set_property(SOURCE UsingUnorderedMap.i PROPERTY CPLUSPLUS ON)
swig_add_library(UsingUnorderedMap
LANGUAGE python
TYPE MODULE
SOURCES UsingUnorderedMap.i UsingUnorderedMap)
set_target_properties(UsingUnorderedMap
PROPERTIES LANGUAGE CXX)
target_include_directories(UsingUnorderedMap PUBLIC
${Python_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(UsingUnorderedMap PUBLIC ${Python_LIBRARIES})
install(TARGETS UsingUnorderedMap DESTINATION UsingUnorderedMap)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/UsingUnorderedMap.py
${CMAKE_CURRENT_SOURCE_DIR}/testUsingUnorderedMap.py
DESTINATION UsingUnorderedMap)
这是一个小例子,显示了 std::unordered_map
到 python 字典的转换
%module dictmap
%{
#include "test.h"
%}
%typemap(out) std::unordered_map<std::string, std::string> (PyObject* obj) %{
obj = PyDict_New();
for (const auto& n : ) {
PyObject* strA = PyUnicode_FromString(n.first.c_str());
PyObject* strB = PyUnicode_FromString(n.second.c_str());
PyDict_SetItem(obj, strA, strB);
Py_XDECREF(strA);
Py_XDECREF(strB);
}
$result = SWIG_Python_AppendOutput($result, obj);
%}
%include "test.h"
小内联函数
#pragma once
#include <string>
#include <unordered_map>
std::unordered_map<std::string, std::string> makeStringMap() {
return std::unordered_map<std::string, std::string> {
{"first", "hello"},
{"second", "world"},
};
}
我希望你能看到你做错了什么。您正在返回一个使用空 $input
创建的空字典。我不确定您是否需要定义一个 PyObject
参数,但我总是这样做,以防需要它与另一个类型映射一起使用。
我正在尝试使用 swig 将无序映射包装在 python 字典中:
// UsingAnUnorderedMap.h
#ifndef LEARNSWIG_USINGUNORDEREDMAP_H
#define LEARNSWIG_USINGUNORDEREDMAP_H
#include <unordered_map>
#include <string>
std::unordered_map<std::string, int> makeStringToIntMap(){
return std::unordered_map<std::string, int>{
{"first", 4},
{"second", 5},
};
}
#endif //LEARNSWIG_USINGUNORDEREDMAP_H
//UsingAnUnorderedMap.i
%module UsingUnorderedMap
%{
#include "UsingUnorderedMap.h"
#include <iostream>
#include <unordered_map>
%}
%include "std_string.i"
%include "std_pair.i"
%include "std_unordered_map.i"
%template(StringToIntMap) std::unordered_map<std::string,int>;
%include "UsingUnorderedMap.h"
%typemap(out) StringToIntMap {
PyDictObject* dict = PyDict_New($input);
for (auto &item: StringToIntMap){
PyDict_SetItem(dict, PyUnicode_FromString(item.first), item.second);
}
$result = dict;
}
# testUsingAnUnorderedMap.py
import sys
sys.path += [
r"D:\LearnSwig\install-msvc\UsingUnorderedMap"
]
import UsingUnorderedMap
print(type(UsingUnorderedMap.makeStringToIntMap()))
这会产生
<class 'UsingUnorderedMap.StringToIntMap'>
即它只是忽略了类型图。从技术上讲,StringToIntMap
的行为与 Python dict 几乎相同 - 据我所知,但我认为 Python 词典中的 Python 用户很舒服,所以它如果这是一本简单的字典会更好。有人对如何实现这一目标有任何指示吗?
为方便起见,您可以使用以下 CMake 代码构建此代码。请注意,我使用命令 -DSWIG_EXECUTABLE=/path/to/swig.exe
.
# CMakeLists.txt
set(Python_ROOT_DIR "C:/Miniconda3")
find_package(Python COMPONENTS Interpreter Development NumPy)
message("Python_EXECUTABLE ${Python_EXECUTABLE}")
find_package(SWIG 4.0.0 REQUIRED
COMPONENTS python
)
include(UseSWIG)
set_property(SOURCE UsingUnorderedMap.i PROPERTY CPLUSPLUS ON)
swig_add_library(UsingUnorderedMap
LANGUAGE python
TYPE MODULE
SOURCES UsingUnorderedMap.i UsingUnorderedMap)
set_target_properties(UsingUnorderedMap
PROPERTIES LANGUAGE CXX)
target_include_directories(UsingUnorderedMap PUBLIC
${Python_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(UsingUnorderedMap PUBLIC ${Python_LIBRARIES})
install(TARGETS UsingUnorderedMap DESTINATION UsingUnorderedMap)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/UsingUnorderedMap.py
${CMAKE_CURRENT_SOURCE_DIR}/testUsingUnorderedMap.py
DESTINATION UsingUnorderedMap)
这是一个小例子,显示了 std::unordered_map
到 python 字典的转换
%module dictmap
%{
#include "test.h"
%}
%typemap(out) std::unordered_map<std::string, std::string> (PyObject* obj) %{
obj = PyDict_New();
for (const auto& n : ) {
PyObject* strA = PyUnicode_FromString(n.first.c_str());
PyObject* strB = PyUnicode_FromString(n.second.c_str());
PyDict_SetItem(obj, strA, strB);
Py_XDECREF(strA);
Py_XDECREF(strB);
}
$result = SWIG_Python_AppendOutput($result, obj);
%}
%include "test.h"
小内联函数
#pragma once
#include <string>
#include <unordered_map>
std::unordered_map<std::string, std::string> makeStringMap() {
return std::unordered_map<std::string, std::string> {
{"first", "hello"},
{"second", "world"},
};
}
我希望你能看到你做错了什么。您正在返回一个使用空 $input
创建的空字典。我不确定您是否需要定义一个 PyObject
参数,但我总是这样做,以防需要它与另一个类型映射一起使用。