如何在pybind11模块中正确检查Python对象的数据类型?
在pybind11中正确检查Python类型的方法
问题重现
你编写的pybind11模块代码如下:
PYBIND11_MODULE(testmodule, m) { // Assume Value class has been exposed here m.def("processDict", [](py::str expr, py::dict valueDict) { std::map<std::string, Value> cppValueDict; for (auto item : d) { // Convert key to std::string std::string key = item.first.cast<std::string>(); // Trying to check python value type and cast it to custom datum type if (pybind11::isinstance(item.second, pybind11::int_) { cppValueDict.insert({key, CustomDatum::createIntDatum(pybind11::cast<int>(item.second))}); } else { cppValueDict.insert({key, CustomDatum::createStringDatum(pybind11::cast<std::string>(item.second))}); } } process(expr, cppValueDict); }); }
当Python脚本传入dict_obj = {"a": 1, "b": "Hello"}调用processDict时,报错:Unable to cast Python instance of type <class 'int'> to C++ type 'std::string',说明int类型的判断未生效,代码走到else分支尝试强制转换int为string导致错误。
错误原因分析
- 循环变量错误:代码中遍历的是未定义的变量
d,实际应遍历函数参数valueDict。 isinstance用法错误:pybind11::isinstance(obj, type)形式的第二个参数需要传入Python类型对象实例,而pybind11::int_是类型模板,并非可直接传入的实例。- 语法错误:if条件语句末尾缺少闭合括号,导致编译逻辑异常。
正确的类型检查方式
pybind11提供两种可靠的类型检查方案:
1. 模板参数形式(推荐用于基础类型)
使用pybind11::isinstance<T>(obj),其中T为pybind11封装的基础类型模板(如pybind11::int_、pybind11::str),这种方式编译期即可确定类型,效率更高:
// 检查是否为int类型 if (pybind11::isinstance<pybind11::int_>(item.second)) { // 处理int类型逻辑 } // 检查是否为字符串类型 else if (pybind11::isinstance<pybind11::str>(item.second)) { // 处理字符串类型逻辑 }
2. 类型对象形式(适用于自定义类型/动态判断)
如果需要检查自定义Python类型,或动态获取类型对象进行判断,可使用pybind11::isinstance(obj, type_obj):
- 基础类型可通过
pybind11::int_()、pybind11::str()获取类型对象实例 - 自定义类型可使用
py::type::of<CustomType>()(需提前暴露该类型),或直接引用暴露时的类型变量
示例:
// 检查基础int类型 if (pybind11::isinstance(item.second, pybind11::int_())) { // 处理逻辑 } // 检查自定义类型CustomType if (pybind11::isinstance(item.second, py::type::of<CustomType>())) { // 处理自定义类型逻辑 }
修正后的完整代码
PYBIND11_MODULE(testmodule, m) { // Assume Value class has been exposed here m.def("processDict", [](py::str expr, py::dict valueDict) { std::map<std::string, Value> cppValueDict; // 修正:遍历正确的函数参数valueDict for (auto item : valueDict) { std::string key = item.first.cast<std::string>(); // 使用模板参数形式的isinstance做类型检查 if (pybind11::isinstance<pybind11::int_>(item.second)) { cppValueDict.insert({key, CustomDatum::createIntDatum(pybind11::cast<int>(item.second))}); } else if (pybind11::isinstance<pybind11::str>(item.second)) { cppValueDict.insert({key, CustomDatum::createStringDatum(pybind11::cast<std::string>(item.second))}); } else { // 可选:添加未支持类型的错误抛出,避免后续转换崩溃 throw pybind11::type_error("Unsupported value type"); } } process(expr, cppValueDict); }); }
内容的提问来源于stack exchange,提问作者Abhishek Anand
相关产品推荐
相关产品推荐

