文章目录
- 前言
- 一、枚举简介
- 1.1 什么是枚举?
- 1.2 枚举的发展历程
- 1.3 为什么需要枚举?
- 1.4 使用枚举的优势
- 二、枚举的基本使用
- 2.1 创建枚举
- 2.2 访问枚举成员
- 2.3 枚举成员比较
- 2.4 确保枚举值唯一
前言
本文主要介绍枚举的基础知识以及枚举的使用方法。
一、枚举简介
1.1 什么是枚举?
枚举是一种特殊的数据类型,用于定义一组具有唯一名称的常量值。枚举中的每个成员都是唯一且不可变的,这使得它们非常适合表示固定的选项集合、状态码、错误代码等。
枚举的特点:
- 唯一性:枚举成员名称和值都是唯一的(可通过装饰器保证)
- 不可变性:枚举成员创建后不能修改
- 可迭代性:可以像集合一样遍历所有成员
- 可比较性:支持恒等比较(is)和值比较(==)
1.2 枚举的发展历程
• Python 3.4 之前:没有内置的枚举类型,需要通过第三方库或自定义类实现
• Python 3.4:引入了 enum 模块,添加了 Enum 类
• Python 3.4 之前的版本可以通过 pip install enum34 安装兼容库
1.3 为什么需要枚举?
不使用枚举的传统方式:
python# 使用大写变量定义常量(传统方式)RED=0GREEN=1BLUE=2BLACK=3WHITE=4defset_color(color_code):ifcolor_code==RED:print("设置为红色")elifcolor_code==GREEN:print("设置为绿色")# ...# 问题:这些"常量"实际上还是变量,可以被修改RED=999# 这会导致程序出错,但Python不会阻止1.4 使用枚举的优势
• 提供类型安全,防止意外的值修改
• 提高代码可读性和可维护性
• 自动文档化,IDE可以提供更好的代码补全
• 防止无效值的使用
二、枚举的基本使用
2.1 创建枚举
基本枚举创建
pythonfromenumimportEnum# 方式1:使用类继承 EnumclassColor(Enum):"""颜色枚举"""RED=1GREEN=2BLUE=3YELLOW=4BLACK=5WHITE=6# 方式2:使用函数式APIWeekday=Enum('Weekday',['MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY','SUNDAY'])# 方式3:使用函数式API并指定值HTTPStatus=Enum('HTTPStatus',[('OK',200),('CREATED',201),('ACCEPTED',202),('BAD_REQUEST',400),('UNAUTHORIZED',401),('FORBIDDEN',403),('NOT_FOUND',404),('INTERNAL_SERVER_ERROR',500)])# 方式4:使用range自动生成值Priority=Enum('Priority',['LOW','MEDIUM','HIGH'],start=1)print("枚举创建演示:")print("-"*50)print(f"颜色枚举:{list(Color)}")print(f"星期枚举:{list(Weekday)}")print(f"HTTP状态枚举:{list(HTTPStatus)}")print(f"优先级枚举:{list(Priority)}")带有方法的枚举 pythonfromenumimportEnumimportmathclassShape(Enum):"""图形枚举,带有计算面积的方法"""CIRCLE=1SQUARE=2TRIANGLE=3RECTANGLE=4defarea(self,*args):"""计算面积"""ifself==Shape.CIRCLE:radius=args[0]returnmath.pi*radius**2elifself==Shape.SQUARE:side=args[0]returnside**2elifself==Shape.TRIANGLE:base,height=argsreturn0.5*base*heightelifself==Shape.RECTANGLE:length,width=argsreturnlength*widthelse:raiseValueError(f"不支持的图形类型:{self}")# 使用示例print("\n带有方法的枚举:")print("-"*50)print(f"圆形面积 (半径=5):{Shape.CIRCLE.area(5):.2f}")print(f"正方形面积 (边长=4):{Shape.SQUARE.area(4)}")print(f"三角形面积 (底=6, 高=3):{Shape.TRIANGLE.area(6,3)}")print(f"矩形面积 (长=8, 宽=5):{Shape.RECTANGLE.area(8,5)}")2.2 访问枚举成员
pythonfromenumimportEnumclassStatus(Enum):"""状态枚举"""PENDING='pending'PROCESSING='processing'COMPLETED='completed'FAILED='failed'print("枚举成员访问演示:")print("="*50)# 1. 通过名称访问print("1. 通过名称访问:")print(f"Status.PENDING ={Status.PENDING}")print(f"类型:{type(Status.PENDING)}")# <enum 'Status'># 2. 通过值访问print("\n2. 通过值访问:")print(f"Status('pending') ={Status('pending')}")print(f"Status['PENDING'] ={Status['PENDING']}")# 3. 访问成员属性print("\n3. 访问成员属性:")member=Status.PENDINGprint(f"成员:{member}")print(f"名称(name):{member.name}")print(f"值(value):{member.value}")print(f"类型:{type(member)}")# 4. 检查成员存在性print("\n4. 检查成员存在性:")print(f"'PENDING' in Status.__members__:{'PENDING'inStatus.__members__}")print(f"'CANCELLED' in Status.__members__:{'CANCELLED'inStatus.__members__}")print(f"'pending' 是否是有效值:{'pending'in[s.valueforsinStatus]}")# 5. 获取所有成员print("\n5. 获取所有成员:")print(f"Status.__members__:{Status.__members__}")print(f"list(Status):{list(Status)}")print(f"len(Status):{len(Status)}")# 6. 遍历枚举print("\n6. 遍历枚举成员:")print("直接遍历:")forstatusinStatus:print(f"{status.name:12}={status.value}")print("\n遍历名称和值:")forname,memberinStatus.__members__.items():print(f"{name:12}={member.value}")2.3 枚举成员比较
pythonfromenumimportEnumclassLogLevel(Enum):"""日志级别枚举"""DEBUG=10INFO=20WARNING=30ERROR=40CRITICAL=50print("枚举成员比较演示:")print("="*50)# 创建一些枚举实例debug1=LogLevel.DEBUG debug2=LogLevel.DEBUG info=LogLevel.INFOprint("1. 恒等比较 (is):")print(f" debug1 is debug2:{debug1isdebug2}")# True - 同一个对象print(f" debug1 is info:{debug1isinfo}")# False - 不同对象print("\n2. 相等比较 (==):")print(f" debug1 == debug2:{debug1==debug2}")# True - 值相同print(f" debug1 == info:{debug1==info}")# False - 值不同print(f" LogLevel.DEBUG == LogLevel(10):{LogLevel.DEBUG==LogLevel(10)}")# Trueprint("\n3. 值比较:")print(f" debug1.value == 10:{debug1.value==10}")# Trueprint(f" debug1.value == info.value:{debug1.value==info.value}")# Falseprint("\n4. 名称比较:")print(f" debug1.name == 'DEBUG':{debug1.name=='DEBUG'}")# Trueprint(f" debug1.name == info.name:{debug1.name==info.name}")# Falseprint("\n5. 身份比较:")print(f" id(debug1) == id(debug2):{id(debug1)==id(debug2)}")# True# 注意:枚举成员不支持大小比较(除非使用IntEnum)print("\n6. 大小比较(会报错):")try:result=LogLevel.DEBUG<LogLevel.INFOprint(f" DEBUG < INFO:{result}")exceptTypeErrorase:print(f" 错误:{e}")2.4 确保枚举值唯一
pythonfromenumimportEnum,uniqueprint("确保枚举值唯一演示:")print("="*50)# 1. 没有 @unique 装饰器的情况(允许重复值)classDuplicateColor(Enum):"""没有唯一性检查的枚举"""RED=1GREEN=2BLUE=3LIGHT_RED=1# 值与RED重复,但这是允许的print("1. 没有 @unique 装饰器:")print(f" RED:{DuplicateColor.RED}")print(f" LIGHT_RED:{DuplicateColor.LIGHT_RED}")print(f" RED == LIGHT_RED:{DuplicateColor.RED==DuplicateColor.LIGHT_RED}")# Trueprint(f" RED is LIGHT_RED:{DuplicateColor.REDisDuplicateColor.LIGHT_RED}")# Trueprint(f" 注意: RED 和 LIGHT_RED 是同一个对象!")# 2. 使用 @unique 装饰器try:@uniqueclassUniqueColor(Enum):"""有唯一性检查的枚举"""RED=1GREEN=2BLUE=3LIGHT_RED=1# 这里会引发 ValueErrorprint("\n2. 使用 @unique 装饰器:")print(" 代码不会执行到这里,因为上面已经报错了")exceptValueErrorase:print(f"\n2. 使用 @unique 装饰器(捕获错误):")print(f" 错误:{e}")# 3. 正确的唯一枚举@uniqueclassProperColor(Enum):"""正确的唯一枚举"""RED=1GREEN=2BLUE=3YELLOW=4BLACK=5WHITE=6print("\n3. 正确的唯一枚举:")forcolorinProperColor:print(f"{color.name:10}={color.value}")# 4. 自动生成唯一值@uniqueclassAutoNumber(Enum):"""使用自动赋值确保唯一性"""FIRST=1SECOND=2THIRD=3FOURTH=4# 如果有很多成员,可以使用自动赋值# 但需要小心确保唯一性print("\n4. 枚举值唯一性的重要性:")print(" 在实际项目中,枚举值唯一性很重要,因为:")print(" - 避免逻辑错误")print(" - 提高代码可读性")print(" - 便于调试和维护")print(" - 防止意外的值冲突")