python - UnicodeDecodeError 与 pybind11
问题描述
我正在尝试包装一个返回字符串的类。
class SS {
public:
SS(const std::string& s) : data_(s.data()), size_(s.size()) {}
// Return a pointer to the beginning of the referenced data
const char* data() const { return data_; }
const char* data_;
size_t size_;
};
class PySS: public SS {
public:
PySS(const std::string &str): SS(str) {
std::cout << "cons " << str << std::endl; #key1
std::cout << "data " << SS::data() << std::endl; # key1
}
std::string data() {
std::cout << "call data " << SS::data() << std::endl; # p��
return std::string(SS::data());
}
};
void init_slice(py::module & m) {
py::class_<PySS>(m, "SS")
.def(py::init<const std::string&>())
.def("data", &PySS::data);
}
从python调用时,
s = SS('key1')
print (s.data())
它抛出 unicode 错误
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 1: invalid start byte
我在构造函数中打印字符串,它显示了相同的结果。但在另一个函数中,它显示了一些未解释的字符串。
任何想法?
[编辑]
这是重现类似问题的最小示例。
class SS {
public:
SS(const std::string& s) : data_(s.data()) {}
// Return a pointer to the beginning of the referenced data
const char* data() const { return data_; }
const std::string ToString() const {
std::cout << std::string(data_) << std::endl;
return std::string(data_);
}
const char* data_;
};
void init_slice(py::module & m) {
py::class_<SS>(m, "Slice")
.def(py::init<const std::string&>())
.def("data", &SS::ToString);
}
解决方案
问题方案
您的示例存在几个问题,最重要的是您的指针无效,因为它们指向超出范围的内容(您的s
参数class SS
)。
解决方法是复制s
到一个成员变量中class SS
,如下:
#include <string>
#include <iostream>
#include <pybind11/pybind11.h>
namespace py = pybind11;
class SS {
public:
SS(const std::string& s) : m_data(s) {}
const char* data() const { return m_data.data(); }
std::string m_data;
};
class PySS: public SS {
public:
PySS(const std::string& s): SS(s) {}
std::string get() { return std::string(SS::data()); }
};
PYBIND11_MODULE(example, m)
{
py::class_<PySS>(m, "SS")
.def(py::init<const std::string&>())
.def("get", &PySS::get);
}
还有两点说明:
- 在您的示例中,缺少宏
PYBIND11_MODULE
,它处理了一些能够导入您的模块的一般事项(请参阅此示例)。 - 我永远不会用两种不同的含义声明同一个函数:你
SS::data()
返回一个指针,而PySS::data()
返回一个副本(astd::string
)。因此,我将后者重命名以PySS::get()
明确区分。
第三方类的解决方法
鉴于您class SS
无法控制它,我认为您只能通过包装它来解决问题。例如:
#include <string>
#include <iostream>
#include <pybind11/pybind11.h>
namespace py = pybind11;
class SS {
public:
SS() = default;
SS(const std::string& s) : data_(s.data()), size_(s.size()) {}
const char* data() const { return data_; }
private:
const char* data_;
size_t size_;
};
class PySS {
public:
PySS(const std::string& s) { m_data = s; m_SS = SS(m_data); }
std::string get() { return std::string(m_SS.data()); }
private:
std::string m_data;
SS m_SS;
};
PYBIND11_MODULE(example, m)
{
py::class_<PySS>(m, "SS")
.def(py::init<const std::string&>())
.def("get", &PySS::get);
}
推荐阅读
- firebase - 即使在查询结果中没有找到文档,Firebase 也会执行“读取”规则
- google-app-engine - 使用 cloudflare DNS 添加 Google 管理的自动续订 SSL 自定义域
- php - Crud 数据库更新帮助
- pandas - 当 Pandas DataFrame 中下一行的所有列都为 NaN 时更新行索引
- ubuntu - 联系 http://controller:5000/v3 时未能发现可用的身份版本
- javascript - Javascript : For 循环内的 For 循环。重复项
- java - 如何在不抛出异常的情况下将字符串转换为 URI
- ios - 使用正交滚动行为的水平uicollectionview中的大差距
- javascript - 从加载回调函数访问外部范围变量
- angular - 连接两个模板变量以作为角度输入