我的现有工作代码取决于boost::uuids::uuid
。现在我试图从中生成一个python模块。 SWIG成功生成了所有重要的类和函数。但是我遇到了带有或返回boost uuid的函数的问题。
我想在boost uuid和python uuid之间进行转换。我可以用任何uuid.i吗?我看到有一个uuid python模块。我知道我可以使用uuid.i
从PyImport_ImportModule("uuid")
导入该模块。
但是如何在typemap
内实例化和使用python的uuid类?
答案 0 :(得分:0)
通过PyImport_ImportModule
调用,您可以通过正确的方式完成任务。您需要做的是弄清楚如何编组两种类型之间的UUID,然后为每个方向编写一个类型图。我最终通过字符串表示,因为这是我在视图中最简单的可移植方式。那是在两个方向上使用uuid_io.hpp的IO运算符。
当我们像这样包装它时,Python代码永远不会看到提升类型,反之亦然。
我假设你在这里瞄准Python 3.4,但我所做的一切都应该是简单的调整以适应旧的Python。
首先,我将一个C ++头文件放在一起,以演示我实现的包装:
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <iostream>
inline boost::uuids::uuid testout() {
static boost::uuids::random_generator gen;
return gen();
}
inline void testin(const boost::uuids::uuid& in) {
std::cout << in << "\n";
}
那里没什么聪明的,每个传递对象的方向都只有一个函数。
接下来我写了一些Python来练习我想要制作的界面:
import test
import uuid
a=test.testout()
print(type(a))
print(a)
b=uuid.uuid4()
print(type(b))
print(b)
test.testin(a)
test.testin(b)
最后一个SWIG接口,一旦我编写了实际的UUID包装,就会生成这个模块。
%module test
%{
#include "test.hh"
%}
%include "boost_uuid.i"
%include "test.hh"
有了这一切,我们现在可以编写一个适用于我们场景的实现boost_uuid.i:
%{
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid.hpp>
#include <sstream>
namespace {
PyObject *py_uuid = nullptr;
}
%}
%init %{
py_uuid = PyImport_ImportModule("uuid"); // Handle error
%}
%typemap(in) const boost::uuids::uuid& (boost::uuids::uuid tmp) {
PyObject *str = PyObject_Str($input);
assert(str); // TODO: check properly
const char *uuid_str = PyUnicode_AsUTF8(str); // Note: Python 3.x, adjust as needed
assert(uuid_str); // TODO: check me
std::istringstream in(uuid_str);
Py_DECREF(str);
in >> tmp; // TODO: Check return!
$1 = &tmp;
}
%typemap(out) boost::uuids::uuid {
// Check this actually works!
static PyObject *uuid_ctor = PyObject_GetAttrString(py_uuid, "UUID");
std::ostringstream out;
out << $1;
PyObject *str = PyUnicode_DecodeUTF8(out.str().c_str(), out.str().size(), NULL);
// Theoretically this string conversion could have just failed
$result = PyObject_CallFunctionObjArgs(uuid_ctor, str, NULL);
Py_DECREF(str);
}
我确实考虑过使用boost::python
来简化一些代码,因为它会提升我们的包装。最后,我并没有为此烦恼。
你也可以使用boost lexical_cast
来避免我使用过的字符串流。这主要是品味问题。
这些都不是超高性能代码,但是当你跨越语言边界时,它也不太可能是你系统中的瓶颈。您可以使用boost和Python的UUID模块提供的逐字节访问,并使其成为直接复制操作,但我避免了这一点,因为需要考虑字节顺序,这增加了复杂性。
注意:
使用此作为起点,所有这些都应该相当容易添加。
这会按预期编译并运行:
swig3.0 -c++ -python -py3 -Wall test.i
g++ -g -std=c++1y -shared test_wrap.cxx -o _test.so -I/usr/include/python3.4 -Wall -Wextra -lpython3.4m
python3.4 run.py
<class 'uuid.UUID'>
b37c9285-f055-4f08-b4e9-4a238be3b09d
<class 'uuid.UUID'>
cf1071e6-2e7f-45af-8920-a68290ee61d4
b37c9285-f055-4f08-b4e9-4a238be3b09d
cf1071e6-2e7f-45af-8920-a68290ee61d4