上下文是嵌入式python脚本并调用解释器 来自用C ++编写的代码。
下面的C ++和Python代码总结了用C ++包装的技术,在Python中使用,然后在C ++中提取两个最常见的STL容器:
它更专注于它们持有std :: string类型元素的情况。
对于不熟悉boost python库的编码人员来说,其中一个难点是,增强迭代器和可迭代套件正在映射这两种语言共有的概念,但在两个相应的编程环境中它们的处理方式却截然不同。
借鉴现有的材料和个人实验,我已经向自己澄清了最常见的用途。没有其他地方没有显示,但它确实感觉就像boost :: python在示例和说明案例方面可以容忍一些冗余。
有一种情况我到目前为止似乎无法解决:将包装的字符串向量返回给C ++。如果有人能够在这方面让我高兴,我将不胜感激。
该代码旨在自包含,有两个目的。首先,它旨在帮助那些像我一样寻找更多简单用例的人。它还表明,操纵double的向量比向量字符串更直接。
在下面的C ++示例中,我得到一个运行时错误,基本上说: typedef std :: vector VecStr; class boost :: python :: class>来自此类型为MapStringVectorString的Python对象的struct boost :: python :: deltail :: not_specified_struc。
任何建议都将不胜感激。
PS:我不得不从内存重构修改后的代码,可能会出现一些语法错误。一旦我可以访问连接的机器,我就会纠正它们。
#include "stdafx.h"
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <Python.h>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::python;
BOOST_PYTHON_MODULE(idctor)
{
typedef std::vector<string> VectorString;
typedef std::map<string, VectorString> MapVectorString;
typedef class_<VectorString, shared_ptr<VectorString>> pyVectorString;
using namespace boost::python;
class_<std::vector<double> >("DoubleVector")
.def(vector_indexing_suite<std::vector<double> >());
class_<std::vector<std::string>,shared_ptr<VectorString> >("VectorString")
.def(vector_indexing_suite<std::vector<string> >());
class_<std::map<std::string, double> >("StringDoubleMap")
.def(map_indexing_suite<std::map<std::string, double> >());
class_<std::map<string, string> >("MapStringString")
.def(map_indexing_suite<std::map<std::string, string> >());
class_<std::map<string, VectorString> , shared_ptr<MapVectorString>>("MapStringVectorString")
.def(map_indexing_suite<std::map<std::string, VectorString> >());
}
typedef std::vector<string> VectorString;
typedef class_<VectorString> pyVectorString;
typedef class_<VectorString, shared_ptr<VectorString>> pyMapVectorString;
int main()
{
PyImport_AppendInittab("idctor", &PyInit_idctor);
Py_Initialize();
try {
//PyInit_hello();
object main
= object(handle<>(borrowed(PyImport_AddModule("__main__"))));
object main_namespace = main.attr("__dict__");
PyRun_SimpleString("import sys\n");
exec_file("G:\\Developments\\VisualStudio\\BoostPythonSTLContainers\\stlcontainers.py", main_namespace);
// Getting back an Python object containing a
// vector of double, extracting the
// corresponding typed C++ object and using it
object pyv = main_namespace["v"];
//----------------> this works <--------------
std::vector<double>& v = extract<vector<double>&>(pyv);
v.push_back(665);
//----------------> this does not <----------------
// Getting back a working Python object
object pyvs = main_namespace["vs"];
// Attempting to convert it back to its true C++ type
// Here the conversion fails:
VectorString& vs = extract<VectorString&>(pyvs);
vs.push_back("not yet the beast");
// Attempt to do the same with a map of string to vector of strings
object pymvs = main_namespace["mvs"];
//----------------> Clearly this fails too <--------------
pyMapVectorString& mvs = extract<pyMapVectorString&>(pymvs);
object pyvs = mvs["this "];
VectorString& vs = extract<VectorString&>(pyvs);
vs.push_back({ "should ","work" });
}
catch (error_already_set) {
PyErr_Print();
return 1;
}
Py_Finalize();
return 0;
}
这是(工作)python代码:
#
# All the python code below is working fine
# (the issue is converting back in C++)
import idctor
#defining a function to print a container
def tostr(container):
string ='['
for i in container:
string += str(i)+","
string+='end]'
return string
# Turning it into a instance method
idctor.DoubleVector.__str__ = tostr
# instantiating a vector of doubles
v = idctor.DoubleVector()
v.append(1.0)
v.append(2.0)
for i in v:
print(i)
#instantiating a vector of strings
idctor.VectorString.__str__ = tostr
vs = idctor.VectorString()
vs.append("he2")
vs.append("he1")
print("Directly: ", vs)
for s in vs:
print(s)
m = idctor.StringDoubleMap()
# instantiating a map of string to doubles
m["a"] = 1
m["b"] = 2
for i in m:
print(i)
print(m)
#instantiating a map of string to strings
ms = idctor.MapStringString()
ms["a"]="he1"
ms["b"]="he2"
for s in ms:
print(s)
#instantiating a map of string to vectors of strings
mvs = idctor.MapStringVectorString()
mvs["a"]=vs
vs2=idctor.VectorString()
vs2.append("cy")
vs2.append("ve")
mvs["b"]=vs2
for vs in mvs:
print(vs)
答案 0 :(得分:1)
可以通过在类的模板声明中输入NoProxy = true选项来纠正第一个问题。第二个问题仍然存在,似乎应该构建一个来自python的特殊转换器来处理这种情况。我还没弄明白该怎么做。然而,我发现依赖于python对象本身的 - 可以说是丑陋的 - 解决方法。只是添加以防有些人想要遵循这条道路。
BOOST_PYTHON_MODULE(idctor)
{
typedef std : : vector <string> VectorString;
typedef std::map<string, VectorString> MapVectorString;
typedef class_<Vector String, shared_ptr<VectorString>> pyVectorString;
using namespace boost::python;
// NOTICE THE TRUE IN THE
// vector_indexing_suite second template argument
class_<std::vector <std::string>, Shared_ptr <VectorString> > ("VectorString")
.def(vector_indexing_suite<std::vector<string>, true >());
class <std::map<std::string, double> > ("StringDoubleMap")
.def(map_indexing_suite<std::map<std::string, double>, true >());
class <std::map<string, string> > ("MapStringString")
.def(map indexing suite<std::map<string, string>, true >());
class <MapVectorString, shared ptrkMapVectorString>, boost::noncopyable>("MapStringVectorString")
.def(map_indexing_suite<MapVectorString, true >());
}
typedef std::vector<string> VectorString;
typedef class_<VectorString> pyVectorString;
typedef std::map<string, VectorString> MapVectorString;
typedef class_<MapVectorString, shared_ptr<MapVectorString>> pyMapVectorString;
int main()
{
PyImport_AppendInittab ("idctor", &PyInit_idctor) ;
Py_Initialize();
try {
object main
= object (handle<> (borrowed (Pylimport_AddModule ("__main__"))));
object main_namespace = main.attr("__dict__");
exec_file ("WrappedSTLContainer.py", main_namespace);
// Getting back a vector of double in C++ and using it
object pyv = main_namespace ["v"];
//- - - - - - - - - - - - - - - - > this works <- - - - - - - - - - - - - -
std::vector<double>& v = extract<vector<double>&>(pyv);
v.push_back(665) ;
// Getting back a vector of string in C++ and attempting to use it
object pyvs = main namespace["vs"];
//- - - - - - - - - - - - - - - - > this works now <- - - - - - - - - - - - - -
std::vector<std::string>& vs = extract<vector<string>&>(pyvs);
vs.push_back("Almost the Beast");
cout << "From C++ this time -> vs[2] " << vs[2] << endl;
// Getting back a map of string-vector of string in C++
// and trying to use it
object pymvs = main namespace["mvs"];
//- - - - - - - - - - - - - - - - > this still does not work - - - - - - - - - - - - - -
// pyMapVectorString& mvs = extract< pyMapVectorString&> (pymvs);
//-------------------------> Work around: working in python
object method = pymvs.attr("__setitem__");
VectorString vs3;
vs3.push_back(" should ");
vs3.push_back("work");
object ignored = method ("this", vs3);
const char * s = extract<const char *> (pymvs.attr("__getitem__")("this ").attr ("__str__") ());
cout << s << endl;
}
catch (error_already_set) {
PyErr_Print();
return 1;
}
Py_Finalize();
return 0;
}