Skip to content

第6章 枚举与常量

C++ 的枚举类型和常量在 Python 中有直接的对应物。本章将介绍如何将枚举导出为 Python 对象,以及如何暴露模块级常量。

enum_basic.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
// C++ 枚举类型
enum class Color {
Red = 1,
Green = 2,
Blue = 3
};
enum class Status {
Pending = 0,
Success = 1,
Error = 2
};
PYBIND11_MODULE(enum_basic, m) {
// 使用 py::enum_<EnumType> 绑定枚举
py::enum_<Color>(m, "Color", py::arithmetic(), "颜色枚举")
.value("RED", Color::Red, "红色")
.value("GREEN", Color::Green, "绿色")
.value("BLUE", Color::Blue, "蓝色")
// 导出到 Python
.export_values();
py::enum_<Status>(m, "Status", py::arithmetic(), "状态枚举")
.value("PENDING", Status::Pending, "待处理")
.value("SUCCESS", Status::Success, "成功")
.value("ERROR", Status::Error, "错误")
.export_values();
}
import enum_basic as eb
print(eb.Color.RED) # <Color.RED: 1>
print(eb.Color.GREEN) # <Color.GREEN: 2>
print(eb.Color.BLUE) # <Color.BLUE: 3>
print(eb.Status.PENDING) # <Status.PENDING: 0>
print(eb.Status.SUCCESS) # <Status.SUCCESS: 1>
c = eb.Color.RED
if c == eb.Color.RED:
print("Color is red") # Color is red
color_val = int(eb.Color.BLUE)
print(color_val) # 3
c1 = eb.Color.RED
c2 = eb.Color.RED
print(c1 is c2) # True
py::enum_<Color>(m, "Color", py::arithmetic(), "docstring")
.value("RED", Color::Red, "RED value")
.export_values();
表达式含义
py::enum_<Color>模板参数是枚举类型
py::arithmetic()启用算术运算(+、- 等),可用于标志位枚举
.value("NAME", Color::Red, "doc")导出枚举值
.export_values()将枚举值导出到模块级别(可以直接用 Color.RED)
enum_export.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
enum class LogLevel {
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3
};
PYBIND11_MODULE(enum_export, m) {
// 方式1: 在模块级别导出枚举值(推荐)
// .export_values() 会把枚举成员导出到模块
py::enum_<LogLevel>(m, "LogLevel", py::arithmetic(), "日志级别")
.value("DEBUG", LogLevel::DEBUG)
.value("INFO", LogLevel::INFO)
.value("WARNING", LogLevel::WARNING)
.value("ERROR", LogLevel::ERROR)
.export_values();
// 方式2: 保留在枚举类内部
// 去掉 .export_values() 后,访问方式是 LogLevel.DEBUG
// 注意:这需要额外定义一个包装类
py::enum_<LogLevel>(m, "LogLevelNoExport", py::arithmetic())
.value("DEBUG", LogLevel::DEBUG)
.value("INFO", LogLevel::INFO)
.value("WARNING", LogLevel::WARNING)
.value("ERROR", LogLevel::ERROR);
// 在 Python 中需要通过 LogLevelNoExport.DEBUG 访问
}
import enum_export as ee
print(ee.LogLevel.DEBUG) # <LogLevel.DEBUG: 0>
print(ee.LogLevel.INFO) # <LogLevel.INFO: 1>
module.LogLevel.DEBUG
// 没有 .export_values()
// 有 .export_values()
// Python: module.DEBUG 或 module.LogLevel.DEBUG 都可以

建议: 大多数情况下使用 .export_values(),这样与 Python 的习惯一致。

enum_compare.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
// 标志位枚举(使用 py::arithmetic())
enum class Permissions {
NONE = 0,
READ = 1,
WRITE = 2,
EXECUTE = 4,
ALL = 7
};
// 普通枚举
enum class Priority {
LOW = 1,
MEDIUM = 2,
HIGH = 3,
CRITICAL = 4
};
PYBIND11_MODULE(enum_compare, m) {
// 标志位枚举(需要 arithmetic 支持)
py::enum_<Permissions>(m, "Permissions", py::arithmetic(), "权限标志")
.value("NONE", Permissions::NONE)
.value("READ", Permissions::READ)
.value("WRITE", Permissions::WRITE)
.value("EXECUTE", Permissions::EXECUTE)
.value("ALL", Permissions::ALL)
.export_values();
py::enum_<Priority>(m, "Priority", "优先级")
.value("LOW", Priority::LOW)
.value("MEDIUM", Priority::MEDIUM)
.value("HIGH", Priority::HIGH)
.value("CRITICAL", Priority::CRITICAL)
.export_values();
}
import enum_compare as ec
p1 = ec.Priority.HIGH
p2 = ec.Priority.HIGH
p3 = ec.Priority.MEDIUM
print(p1 == p2) # True
print(p1 != p3) # True
print(p1 > p3) # True
print(p1 >= p3) # True
print(p1 < p3) # False
r = ec.Permissions.READ
w = ec.Permissions.WRITE
perm = r | w
print(int(perm)) # 3
has_read = perm & r
print(has_read == r) # True
all_perms = ec.Permissions.READ | ec.Permissions.WRITE | ec.Permissions.EXECUTE
print(int(all_perms)) # 7
模式支持的操作
无 py::arithmetic()==, !=, <, >, <=, >=
有 py::arithmetic()以上全部 + +, -, &, `

何时使用: 如果枚举用于标志位(如权限、选项组合),需要 py::arithmetic()。普通顺序枚举不需要。

enum_to_string.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
enum class HttpStatus {
OK = 200,
NOT_FOUND = 404,
INTERNAL_ERROR = 500
};
PYBIND11_MODULE(enum_to_string, m) {
py::enum_<HttpStatus>(m, "HttpStatus", "HTTP 状态码")
.value("OK", HttpStatus::OK)
.value("NOT_FOUND", HttpStatus::NOT_FOUND)
.value("INTERNAL_ERROR", HttpStatus::INTERNAL_ERROR)
.export_values();
// 添加自定义方法
py::enum_<HttpStatus>(m, "HttpStatusEx", "HTTP 状态码(扩展)")
.value("OK", HttpStatus::OK)
.value("NOT_FOUND", HttpStatus::NOT_FOUND)
.value("INTERNAL_ERROR", HttpStatus::INTERNAL_ERROR)
.def("__repr__", [](HttpStatus status) {
switch (status) {
case HttpStatus::OK: return "HttpStatus.OK (200)";
case HttpStatus::NOT_FOUND: return "HttpStatus.NOT_FOUND (404)";
case HttpStatus::INTERNAL_ERROR: return "HttpStatus.INTERNAL_ERROR (500)";
}
return "Unknown";
})
.def_property_readonly("code", [](HttpStatus status) {
return static_cast<int>(status);
}, "获取状态码数值")
.export_values();
}
import enum_to_string as ets
status = ets.HttpStatus.OK
print(status) # <HttpStatus.OK: 200>
print(repr(status)) # <HttpStatus.OK: 200>
status_ex = ets.HttpStatusEx.OK
print(status_ex) # HttpStatus.OK (200)
print(status_ex.code) # 200
print(str(status)) # <HttpStatus.OK: 200>
print(status.name) # OK
print(status.value) # 200
print(eb.HttpStatus.OK.name) # "OK"
print(eb.HttpStatus.OK.value) # 200
for status in eb.HttpStatus:
print(f"{status.name} = {status.value}")
module_constants.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
// 常量定义
constexpr double PI = 3.141592653589793;
constexpr double E = 2.718281828459045;
constexpr int MAX_CONNECTIONS = 1000;
// 使用 py::object 导出常量
PYBIND11_MODULE(module_constants, m) {
m.doc() = "模块级常量演示";
// 直接导出数值常量
m.attr("PI") = py::cast(PI);
m.attr("E") = py::cast(E);
m.attr("MAX_CONNECTIONS") = py::cast(MAX_CONNECTIONS);
// 导出字符串常量
m.attr("VERSION") = py::str("1.0.0");
m.attr("APP_NAME") = py::str("MyApp");
// 导出复杂常量(字典)
py::dict config;
config["debug"] = py::bool_(true);
config["timeout"] = py::int_(30);
config["max_retries"] = py::int_(3);
m.attr("DEFAULT_CONFIG") = config;
// 导出列表
py::list supported_versions;
supported_versions.append(py::str("1.0"));
supported_versions.append(py::str("1.1"));
supported_versions.append(py::str("2.0"));
m.attr("SUPPORTED_VERSIONS") = supported_versions;
}
import module_constants as mc
print(mc.PI) # 3.141592653589793
print(mc.E) # 2.718281828459045
print(mc.MAX_CONNECTIONS) # 1000
print(mc.VERSION) # 1.0.0
print(mc.APP_NAME) # MyApp
print(mc.DEFAULT_CONFIG) # {'debug': True, 'timeout': 30, 'max_retries': 3}
print(mc.DEFAULT_CONFIG["debug"]) # True
print(mc.SUPPORTED_VERSIONS) # ['1.0', '1.1', '2.0']
// 模块级别常量
m.attr("NAME") = value;
// 类属性
py::class_<MyClass>(m, "MyClass")
.attr("CLASS_ATTR") = some_value;
方法用途
m.attr("name") = value设置模块级属性/常量
.attr("name") = value设置类属性

注意: 直接使用 m.attr("x") = 5 导出 int 常量可能有类型问题。推荐使用 py::cast(value) 确保类型正确。

mixed_constants.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
// 错误码枚举
enum class ErrorCode {
SUCCESS = 0,
NOT_FOUND = 404,
PERMISSION_DENIED = 403,
INTERNAL_ERROR = 500
};
// 错误信息映射
static const char* ERROR_MESSAGES[] = {
"Success",
"Not found",
"Permission denied",
"Internal error"
};
PYBIND11_MODULE(mixed_constants, m) {
// 绑定枚举
py::enum_<ErrorCode>(m, "ErrorCode", py::arithmetic())
.value("SUCCESS", ErrorCode::SUCCESS)
.value("NOT_FOUND", ErrorCode::NOT_FOUND)
.value("PERMISSION_DENIED", ErrorCode::PERMISSION_DENIED)
.value("INTERNAL_ERROR", ErrorCode::INTERNAL_ERROR)
.export_values();
// 添加获取错误信息的方法
m.def("get_error_message", [](ErrorCode code) {
return py::str(ERROR_MESSAGES[static_cast<int>(code)]);
}, py::arg("code"), "获取错误码对应的错误信息");
// 导出成功标志常量
m.attr("ERR_SUCCESS") = py::cast(static_cast<int>(ErrorCode::SUCCESS));
m.attr("ERR_NOT_FOUND") = py::cast(static_cast<int>(ErrorCode::NOT_FOUND));
}
import mixed_constants as mc
code = mc.ErrorCode.NOT_FOUND
print(code) # <ErrorCode.NOT_FOUND: 404>
print(code.value) # 404
print(mc.ERR_SUCCESS) # 0
print(mc.ERR_NOT_FOUND) # 404
print(mc.get_error_message(mc.ErrorCode.NOT_FOUND)) # Not found
def handle_error(code):
if code == mc.ErrorCode.SUCCESS:
return "OK"
elif code == mc.ErrorCode.NOT_FOUND:
return "Resource not found"
else:
return "Unknown error"
print(handle_error(mc.ErrorCode.SUCCESS)) # OK
print(handle_error(mc.ErrorCode.NOT_FOUND)) # Resource not found

本章介绍了 pybind11 中枚举和常量的导出方法:

主题关键点
枚举绑定py::enum_<Enum>(m, "Name")
枚举值导出.value("NAME", Enum::Value) + .export_values()
算术运算py::arithmetic() 支持位运算标志位
枚举比较支持 ==, !=, <, > 等比较操作
枚举字符串使用 .def("__repr__", ...) 自定义表示
模块常量m.attr("NAME") = py::cast(value)
混合使用枚举 + 常量 + 辅助函数组合使用

最佳实践: 为枚举提供有意义的 docstring,在 Python 中能方便地通过 help(MyEnum) 查看。

下一章我们将学习智能指针与 pybind11 的集成,这是高级绑定的核心技术之一。