Python 使用 pybind11 和 std::filesystem 作为函数参数的绑定给出 TypeError
Python bindings using pybind11 with std::filesystem as function argument giving TypeError
我有一个 class Foo() 和 class Foo() 有一个声明如下的函数:
bool Foo::copyFile(const std::filesystem::path& src, const std::filesystem::path& dest)
要求是 class Foo 应该有 Python 绑定。我正在使用 pybind11 创建 Python 绑定。
我编写了以下内容来创建 Python 绑定:
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "Foo.h"
namespace py = pybind11;
PYBIND11_MODULE(TestModule, m) {
py::class_ <Foo>(m, "Foo")
.def(py::init())
.def("copyFile",&Foo::copyFile);
};
编译成功,我可以创建 Python 绑定 pyd 文件。
当我使用 Python 绑定 class Foo 使用:
from TestModule import Foo
f = Foo()
ret = f.copyFile("C:\Users\csaikia\Downloads\testfile_src", "C:\Users\csaikia\Downloads\testfile_dest")
它给出了类型错误。我怀疑它与 pybind11 对 c++17 中 std::filesystem 的支持有关,因为我没有看到 class 的其他功能发生这种情况 std::string
或 std::vector
.
我得到的错误是:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: copyFile(): incompatible function arguments. The following argument types are supported:
1. (self: TestModule.Foo, arg0: std::filesystem::path, arg1: std::filesystem::path) -> bool
Invoked with: <TestModule.Foo object at 0x0000000002A33ED8>, 'C:\Users\csaikia\Downloads\testfile_src', 'C:\Users\csaikia\Downloads\testfile_dest'
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.
我是 pybind11 的新手。有人可以帮我解决这个问题吗?
来自我与 pybind11 开发者的对话:
“Pybind 不知道如何将 py::str
转换为 std::filesystem::path
。没有可用的施法者,也没有绑定 std::filesystem::path
class。
最简单的方法是不直接绑定 Foo::copyFile
。而是绑定一个接受 const Foo&
和 const std::string&
作为参数的 lambda,然后您可以将 std::string
传递给 copyFile
,其中 std::filesystem::path
是预期的,让 C++ 隐式转换发生.
你也可以做 py::class_<std::filesystem::path>
并为 std::string
转换器建立绑定,然后使用 py::implicitly_convertible
让所有 C++ 隐式构造发生在 python 端,但是...嗯,工作量太大了。"
它就像一个魅力!
只需将以下行添加到您的绑定中(假设 py::module& m
)。
py::class_<std::filesystem::path>(m, "Path")
.def(py::init<std::string>());
py::implicitly_convertible<std::string, std::filesystem::path>();
这是基于@user304255 描述的后一种方法。
我有一个 class Foo() 和 class Foo() 有一个声明如下的函数:
bool Foo::copyFile(const std::filesystem::path& src, const std::filesystem::path& dest)
要求是 class Foo 应该有 Python 绑定。我正在使用 pybind11 创建 Python 绑定。
我编写了以下内容来创建 Python 绑定:
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "Foo.h"
namespace py = pybind11;
PYBIND11_MODULE(TestModule, m) {
py::class_ <Foo>(m, "Foo")
.def(py::init())
.def("copyFile",&Foo::copyFile);
};
编译成功,我可以创建 Python 绑定 pyd 文件。 当我使用 Python 绑定 class Foo 使用:
from TestModule import Foo
f = Foo()
ret = f.copyFile("C:\Users\csaikia\Downloads\testfile_src", "C:\Users\csaikia\Downloads\testfile_dest")
它给出了类型错误。我怀疑它与 pybind11 对 c++17 中 std::filesystem 的支持有关,因为我没有看到 class 的其他功能发生这种情况 std::string
或 std::vector
.
我得到的错误是:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: copyFile(): incompatible function arguments. The following argument types are supported:
1. (self: TestModule.Foo, arg0: std::filesystem::path, arg1: std::filesystem::path) -> bool
Invoked with: <TestModule.Foo object at 0x0000000002A33ED8>, 'C:\Users\csaikia\Downloads\testfile_src', 'C:\Users\csaikia\Downloads\testfile_dest'
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.
我是 pybind11 的新手。有人可以帮我解决这个问题吗?
来自我与 pybind11 开发者的对话:
“Pybind 不知道如何将 py::str
转换为 std::filesystem::path
。没有可用的施法者,也没有绑定 std::filesystem::path
class。
最简单的方法是不直接绑定 Foo::copyFile
。而是绑定一个接受 const Foo&
和 const std::string&
作为参数的 lambda,然后您可以将 std::string
传递给 copyFile
,其中 std::filesystem::path
是预期的,让 C++ 隐式转换发生.
你也可以做 py::class_<std::filesystem::path>
并为 std::string
转换器建立绑定,然后使用 py::implicitly_convertible
让所有 C++ 隐式构造发生在 python 端,但是...嗯,工作量太大了。"
它就像一个魅力!
只需将以下行添加到您的绑定中(假设 py::module& m
)。
py::class_<std::filesystem::path>(m, "Path")
.def(py::init<std::string>());
py::implicitly_convertible<std::string, std::filesystem::path>();
这是基于@user304255 描述的后一种方法。