如何让pybind11静态只读属性的文档字符串在Python中显示?
问题:pybind11绑定的Logger类静态属性文档在Python3.6的help中不显示
我用pybind11将C++的Logger类绑定到Python,代码中给静态只读属性传递了文档字符串,但在Python3.6中执行help(Logger)时,这些属性的描述为空。绑定代码如下:
py::class_<Logger> logger(m, "Logger"); logger.doc() = "class docstring"; logger.def("setLevels", [](uint16_t levels) { LoggerInstance.setLevels(levels); }, R"( Turns on/off different logging levels Parameters * levels Logging level flags )" ); //expose values as constant fields logger.def_property_readonly_static("LOG_NONE", [](py::object /* self */){return LOG_NONE;}, "no log level turned on"); logger.def_property_readonly_static("LOG_INFO", [](py::object /* self */){return LOG_INFO;}, "info level logs turned on"); logger.def_property_readonly_static("LOG_DEBUG", [](py::object /* self */){return LOG_DEBUG;}, "debug level logs turned on"); logger.def_property_readonly_static("LOG_WARN", [](py::object /* self */){return LOG_WARN;}, "warning logs turned on"); logger.def_property_readonly_static("LOG_ERROR", [](py::object /* self */){return LOG_ERROR;}, "error logs turned on");
解决方案
在Python3.6及更早版本中,pybind11的def_property_readonly_static方法无法正确将文档字符串关联到属性的__doc__字段,导致help输出中没有描述。可以通过以下两种方式解决:
方法1:手动为静态属性设置文档字符串
先通过attr将常量添加为Logger类的属性,再调用pybind11的内部工具函数为属性设置文档。注意:如果是整数等内置类型实例,Python不允许直接修改其__doc__,这种情况下建议改用方法2。
修改后的代码:
py::class_<Logger> logger(m, "Logger"); logger.doc() = "class docstring"; logger.def("setLevels", [](uint16_t levels) { LoggerInstance.setLevels(levels); }, R"( Turns on/off different logging levels Parameters * levels Logging level flags )" ); // 直接添加静态属性到类 logger.attr("LOG_NONE") = LOG_NONE; logger.attr("LOG_INFO") = LOG_INFO; logger.attr("LOG_DEBUG") = LOG_DEBUG; logger.attr("LOG_WARN") = LOG_WARN; logger.attr("LOG_ERROR") = LOG_ERROR; // 手动设置每个属性的文档字符串 py::detail::set_docstring(logger.attr("LOG_NONE").ptr(), "no log level turned on"); py::detail::set_docstring(logger.attr("LOG_INFO").ptr(), "info level logs turned on"); py::detail::set_docstring(logger.attr("LOG_DEBUG").ptr(), "debug level logs turned on"); py::detail::set_docstring(logger.attr("LOG_WARN").ptr(), "warning logs turned on"); py::detail::set_docstring(logger.attr("LOG_ERROR").ptr(), "error logs turned on");
方法2:改用枚举类型绑定(推荐)
将日志级别定义为C++枚举,通过pybind11的enum_绑定为Python枚举。枚举成员的文档字符串会被Python的help系统正确识别,同时语义更清晰,代码可维护性更强。
步骤1:在C++中定义枚举
enum class LogLevel : uint16_t { LOG_NONE = 0, LOG_INFO = 1 << 0, LOG_DEBUG = 1 << 1, LOG_WARN = 1 << 2, LOG_ERROR = 1 << 3 };
步骤2:绑定枚举并关联到Logger类
// 绑定枚举类型 py::enum_<LogLevel>(m, "LogLevel") .value("LOG_NONE", LogLevel::LOG_NONE, "no log level turned on") .value("LOG_INFO", LogLevel::LOG_INFO, "info level logs turned on") .value("LOG_DEBUG", LogLevel::LOG_DEBUG, "debug level logs turned on") .value("LOG_WARN", LogLevel::LOG_WARN, "warning logs turned on") .value("LOG_ERROR", LogLevel::LOG_ERROR, "error logs turned on") .export_values(); // 绑定Logger类 py::class_<Logger> logger(m, "Logger"); logger.doc() = "class docstring"; logger.def("setLevels", [](uint16_t levels) { LoggerInstance.setLevels(static_cast<uint16_t>(levels)); }, R"( Turns on/off different logging levels Parameters * levels Logging level flags (can use LogLevel enum values) )" ); // 可选:将枚举成员附加到Logger类,保持原有调用方式 logger.attr("LOG_NONE") = LogLevel::LOG_NONE; logger.attr("LOG_INFO") = LogLevel::LOG_INFO; logger.attr("LOG_DEBUG") = LogLevel::LOG_DEBUG; logger.attr("LOG_WARN") = LogLevel::LOG_WARN; logger.attr("LOG_ERROR") = LogLevel::LOG_ERROR;
这样无论是help(LogLevel)还是help(Logger.LOG_NONE),都能正确显示对应的文档字符串。
内容的提问来源于stack exchange,提问作者G. B.
相关产品推荐
相关产品推荐

