带有pybind11的UnicodeDecodeError

时间:2019-04-23 03:32:25

标签: python 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);
}

1 个答案:

答案 0 :(得分:0)

问题与解决方案

您的示例存在多个问题,最重要的是您的指针无效,因为它们指向超出范围的内容(您的s的{​​{1}}参数)。

解决方案是将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); } ,该宏处理了一些一般的事情,以便能够导入您的模块(请参见this example)。
  • 我永远不会声明具有两个不同含义的同一函数:您的PYBIND11_MODULE返回一个指针,而SS::data()返回一个副本(一个PySS::data())。因此,我将后者重命名为std::string以便区分。

第三方类的解决方法

鉴于您PySS::get()无法控制自己,我认为您只能通过包装解决该问题。例如:

class SS