9

我使用 Python 2 API 封装了很多 C++(由于各种技术原因,我不能使用 swig 或 boost.python 之类的东西)。当我必须将一个字符串(通常是一个路径,总是 ASCII)传递给 C/C++ 时,我使用这样的东西:

std::string file_name = PyString_AsString(py_file_name); 
if (PyErr_Occurred()) return NULL; 

现在我正在考虑更新到PyString_*不存在方法的 Python 3。我找到了一个解决方案,说我应该做这样的事情:

PyObject* bytes = PyUnicode_AsUTF8String(py_file_name);
std::string file_name = PyBytes_AsString(bytes); 
if (PyErr_Occurred()) return NULL; 
Py_DECREF(bytes); 

然而,这是行数的两倍,而且看起来有点难看(更不用说如果我忘记了最后一行,它可能会导致内存泄漏)。

另一种选择是重新定义python函数以对bytes对象进行操作,并像这样调用它们

def some_function(path_name):
    _some_function(path_name.encode('utf8'))

这并不可怕,但它确实需要每个函数的 python 端包装器。

有没有更清洁的方法来处理这个问题?

4

3 回答 3

5

看起来解决方案存在于 python 3.3 中,带有char* PyUnicode_AsUTF8(PyObject* unicode). PyString_AsString()这应该与 python 2中的函数完全相同。

于 2013-07-08T03:27:36.870 回答
1

如果您知道(当然,您可以使用断言或类似方式检查)它都是 ASCII,那么您可以像这样简单地创建它:

std::string py_string_to_std_string(PyUnicode_string py_file_name)
{
    len = length of py_file_name;     // Not sure how you write that in python. 
    std::string str(len); 
    for(int i = 0; i < len; i++)
        str += py_file_name[i]; 
    return str;
}
于 2013-07-07T21:34:58.060 回答
1

提供接受的答案的改进版本,而不是PyUnicode_AsUTF8(...)更好地使用PyUnicode_AsUTF8AndSize(...)

因为字符串可能在中间某处包含空字符(0 代码点),那么std::string如果您使用PyUnicode_AsUTF8(...).

Py_ssize_t size = 0;
char const * pc = PyUnicode_AsUTF8AndSize(obj, &size);
std::string s;
if (pc)
    s = std::string(pc, size);
else
    // Error, handle!
于 2021-01-13T12:42:21.640 回答