文章目录

  • 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)()

结合枚举实现了函数多态的效果,类似工厂模式,本文提供一个思路,给各位借鉴。