1

我试图公开一个将 const wchar_t* 作为 python 参数的 c++ 函数。在我看来,const wchar_t* 不是一种受支持的输入类型,它会自动公开为 python 字符串,然后像普通的 const char* 一样自动转换。

是否可以添加某种类型的输入类型转换器来自动实现这一点?我知道我可以添加蹦床函数并自己进行 unicode 转换,但让它自动运行会更方便。

我的 boost 版本是 1.52,我正在 64 位 Windows 上使用 python 2.7。

这是显示问题的简单 c++ 序列的示例代码:

#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
void testWcharParam(const wchar_t* str) {
    std::wcout << str << std::endl;
}
void testCharParam(const char* str) {
    std::wcout << str << std::endl;
}
BOOST_PYTHON_MODULE(test)
{
    def("testWcharParam", testWcharParam);
    def("testCharParam", testCharParam);
}

在 python 中导入和运行它时,我得到以下结果:

>>> import test
>>> test.testCharParam('test')
test
>>> test.testWcharParam('test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    test.testWcharParam(str)
did not match C++ signature:
    testWcharParam(wchar_t const * __ptr64)
>>>

出于某种原因,此处的字符串方法http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html#custom_string不适用于原始 wchar_t*。

编辑:添加了缺少的包含和平台信息。

编辑:在 boost 文档中添加了关于示例的注释

4

3 回答 3

3

据我所知,没有办法将 Python 窄字符串 ( str) 自动转换为const wchar_t*.

当 Boost.Python 尝试从 Python 对象转换时,它会在堆栈上分配内存以保存目标类型,然后尝试定位为目标类型注册的转换器。在这种情况下,目标类型将是const wchar_t*. 一旦转换器表明它PyObject是转换的有效候选者,转换就会发生,并在堆栈分配的内存中初始化目标类型。由于 Python/C API 只支持PyObject在编码时创建一个新的,内存管理成为一个问题,因为 Boost.Python 只为wchar_t*.

由于 Boost.Python 没有提供在使用转换后的值后调用的后挂钩,一个简单的折衷方案可能是将参数类型更改const wchar_t*std::wstring。由于std::wstring管理自己的内存,Boost.Python 可以将PyObject宽字符串复制到其中。此外,必要时,Boost.Python 会在转换为std::wstring.

示例代码:

#include <iostream>
#include <boost/python.hpp>

void testWcharParam(std::wstring str) { std::wcout << str << std::endl; }
void testCharParam(const char* str)   { std::wcout << str << std::endl; }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("testWcharParam", testWcharParam);
  python::def("testCharParam", testCharParam);
}

用法:

>>> import example
>>> example.testCharParam('test 1')
test 1
>>> example.testWcharParam(u'test 2')
test 2
>>> example.testWcharParam('test 3')
test 3
于 2013-10-18T17:45:38.407 回答
1

我没有使用过 Boost Python,但是 Python 2 中的 wchar_t 是一个 Unicode 字符串,所以试试:

>>> test.testWcharParam(u'test')
于 2013-10-16T02:29:55.227 回答
1

这就是我最终使用的:

void* convert_to_wcstring(PyObject* obj)
{
    if(PyString_Check(obj)) {
        throw_error_already_set();
    } else if(PyUnicode_Check(obj)) {
        return PyUnicode_AsUnicode(obj);
    }
    throw_error_already_set();
    return 0;
}

然后将其作为转换器添加到:

BOOST_PYTHON_MODULE(test)
{
    converter::registry::insert(convert_to_wcstring, type_id<wchar_t>(),&converter::wrap_pytype<&PyString_Type>::get_pytype);
    ...
}

只要输入参数是 unicode 类型而不是普通的字符串类型,它就可以工作。对于我最初的示例,它将给出以下结果:

# Works
test.testWcharParam(u'test')

# Doesn't work
test.testWcharParam('test')

在我的情况下,C++ API 比 python API 更严格,这意味着我在清理输入字符串方面比在 C++ 端要好得多。

感谢所有答案,您引导我朝着正确的方向前进,但我不得不稍微调整一下,以便找到解决我确切用例的东西。

于 2013-10-22T00:20:52.510 回答