文章目录
- 1. 什么是枚举
- 2. Python 枚举入门
- 2.1 导入Enum模块
- 2.2 定义枚举类
- 2.3 枚举类的特性与用法
- 3. 枚举的进阶玩法
- 3.1 判断成员是否在枚举中
- 3.2 用枚举实现“多态”
- 3.2.1 优化前
- 3.2.2 优化后
1. 什么是枚举
枚举(Enumeration,简称 Enum)是一种特殊的类型或数据结构,在许多编程语言中都有实现,包括 Python。它主要用于定义一组命名的常量集合,这些常量通常表示某种状态、选项或者类别,并且每个枚举成员都是独一无二的。
在 Python 中,可以通过定义一个枚举类,你可以声明一系列具有名称和值的成员。这些成员是单例的,即它们不能被复制,确保了同一枚举类中的不同成员之间不会混淆。
2. Python 枚举入门
在 Python 中,enum
(枚举)模块提供了创建枚举类型的功能。枚举是一种特殊的类,它的实例集合是有限且预定义的,每个实例代表一个唯一的值。这在编写需要确保变量只能取某些特定值的情况下非常有用,可以提高代码的可读性和减少错误。
以下是 Python enum
的入门玩法:
2.1 导入Enum模块
from enum import Enum, IntEnum, auto
-
Enum
:基础枚举类,成员可以是任意不可变类型(如字符串、数字等)。 -
IntEnum
:继承自Enum
,其成员默认为整数类型,同时拥有整数的所有属性和方法。 -
auto()
:在定义枚举时,可以自动为成员分配递增的数值。
2.2 定义枚举类
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
class Weekday(IntEnum):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
class HTTPStatus(Enum):
OK = 200
CREATED = 201
BAD_REQUEST = 400
NOT_FOUND = 404
INTERNAL_SERVER_ERROR = 500
# 使用auto()自动编号
class AutoNumberEnum(Enum):
AUTO_1 = auto()
AUTO_2 = auto()
2.3 枚举类的特性与用法
- 访问枚举成员:
print(Color.RED) # 输出: Color.RED
print(Weekday.MONDAY) # 输出: Weekday.MONDAY
- 获取枚举成员的名称和值:
print(Color.RED.name) # 输出: 'RED'
print(Color.RED.value) # 输出: 1
- 判断是否是枚举成员:
is_red = Color('RED') == Color.RED # 输出: True
- 遍历枚举类的所有成员:
for day in Weekday:
print(day.name, day.value)
- 确保唯一性:枚举的一个重要特性就是保证了所有实例都是独一无二的,无法通过不同方式创建相同的枚举实例。
- 自定义枚举类的方法和属性:枚举类可以像普通类一样添加方法和属性。
3. 枚举的进阶玩法
3.1 判断成员是否在枚举中
如下例子:
class Weekday(IntEnum):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
@classmethod
def is_in(cls, weekday: int) -> bool:
for v in cls.__members__.values():
if weekday == v.value:
return True
# 或者以下用法
for v in cls:
if weekday == v.value:
return True
return False
3.2 用枚举实现“多态”
这里的思路有点像工厂模式,我这里就不用工厂模式实现了,而是利用枚举去实现“函数调用的多态”~
3.2.1 优化前
有这么一种场景,很多的 Python 包都定义了同一个名字的函数,如果在主流程每次都调用会导致整体逻辑显得特别重复、特别冗长,例如:
from pkg import test1, test2, test3, test3, test4
if __name__ == '__main__':
test1.run()
test2.run()
test3.run()
test4.run()
...
例如,python 包 pkg/test1.py
pkg/test2.py
…都存在一个函数:
def run()
print("")
这么看起来好像也没啥,不就是多写一些呗。但是如果后续再增加一个函数调用,那么 main
函数主流程逻辑会显得很冗长。
3.2.2 优化后
我们可以定义一个枚举
class MyFunc(Enum):
func1 = "test1"
func2 = "test2"
func3 = "test3"
func4 = "test4"
@classmethod
def is_in(cls, func_name: str) -> bool:
for v in cls:
if func_name == v.value:
return True
return False
再定义一个类,用于返回具体的函数:
from pkg import test1, test2, test3, test3, test4
class FuncSelector:
@staticmethod
def select_func(func_name: str) -> Callable:
"""
返回对应的 func 方法
:param func_name: 函数名字
:return:
"""
if not MyFunc.is_in(func_name):
raise ValueError("xxxx")
if func_name == MyFunc.func1.value:
return test1.run
elif func_name == MyFunc.func2.value:
return test2.run
elif func_name == MyFunc.func3.value:
return test3.run
elif func_name == MyFunc.func4.value:
return test4.run
def default_func():
print("xx")
return default_func
主函数的调用:
if __name__ == '__main__':
for v in MyFunc:
log.info(f'ready to convert dataset {v.value}')
FuncSelector.select_func(v.value)()
结合枚举实现了函数多态的效果,类似工厂模式,本文提供一个思路,给各位借鉴。