什么是枚举?
枚举(enumerate
)是Python内置函数。在python中枚举是一种类(Enum,IntEnum),存放在enum模块中。枚举类型可以给一组标签赋予一组特定的值。
枚举的特点
枚举类中不能存在相同的标签名
枚举是可迭代的
不同的枚举标签可以对应相同的值,但它们都会被视为该值对应第一个标签的别名
如果要限制定义枚举时,不能定义相同值的成员。可以使用装饰器@unique
枚举成员之间不能进行大小比较,可进行等值和同一性比较
枚举成员为单例,不可实例化,不可更改
定义枚举
01. 直接创建类似枚举结构的变量
1 2 3 4 5 >>> RED, GREEN, YELLOW = range (3 )>>> RED0 >>> GREEN1
02.使用 Enum
来创建枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> from enum import Enum>>> class Day (Enum ):... MONDAY = 1 ... TUESDAY = 2 ... WEDNESDAY = 3 ... THURSDAY = 4 ... FRIDAY = 5 ... SATURDAY = 6 ... SUNDAY = 7 ... >>> type (Day.MONDAY)<enum 'Day' >>> type (Day.TUESDAY)<enum 'Day' >
也可以结合 01, 和 02 一起创建枚举的类. 1 2 3 4 5 6 7 8 9 10 11 12 13 >>> from enum import Enum>>> class Season (Enum ):... WINTER, SPRING, SUMMER, FALL = range (1 , 5 )... >>> list (Season)[ <Season.WINTER: 1 >, <Season.SPRING: 2 >, <Season.SUMMER: 3 >, <Season.FALL: 4 > ]
继承 Enmu
的类还可以被再次继承: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 >>> from enum import Enum>>> import string>>> class BaseTextEnum (Enum ):... def as_list (self ):... try :... return list (self.value)... except TypeError:... return [str (self.value)]... >>> class Alphabet (BaseTextEnum ):... LOWERCASE = string.ascii_lowercase... UPPERCASE = string.ascii_uppercase... >>> Alphabet.LOWERCASE.as_list()['a' , 'b' , 'c' , 'd' , ..., 'x' , 'y' , 'z' ]
### 03.使用 Enum
的 API
来创建枚举类 #### 可以使用 list
来快速创建映射.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 >>> from enum import Enum>>> HTTPStatusCode = Enum(... value="HTTPStatusCode" ,... names=[... ("OK" , 200 ),... ("CREATED" , 201 ),... ("BAD_REQUEST" , 400 ),... ("NOT_FOUND" , 404 ),... ("SERVER_ERROR" , 500 ),... ],... )>>> list (HTTPStatusCode)[ <HTTPStatusCode.OK: 200 >, <HTTPStatusCode.CREATED: 201 >, <HTTPStatusCode.BAD_REQUEST: 400 >, <HTTPStatusCode.NOT_FOUND: 404 >, <HTTPStatusCode.SERVER_ERROR: 500 > ]
使用auto()
的方法来帮助创建枚举
Python
的enum模块提供了一个方便的函数auto(),该函数允许您为枚举成员设置自动值。此函数的默认行为是将连续整数值分配给成员.
您需要为auto()所需的每个自动值调用一次。您还可以auto()与具体值组合,就像您在本例中使用Day.WEDNESDAYand所做的那样Day.SUNDAY。
默认情况下,auto()从
开始为每个目标成员分配连续整数1。您可以通过覆盖该._generate_next_value_()方法来调整此默认行为,该方法auto()在后台使用来生成自动值。
auto() 方法可以自动检测数字.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 >>> from enum import auto, Enum>>> class Day (Enum ):... MONDAY = auto()... TUESDAY = auto()... WEDNESDAY = 3 ... THURSDAY = auto()... FRIDAY = auto()... SATURDAY = auto()... SUNDAY = 7 ... >>> list (Day)[ <Day.MONDAY: 1 >, <Day.TUESDAY: 2 >, <Day.WEDNESDAY: 3 >, <Day.THURSDAY: 4 >, <Day.FRIDAY: 5 >, <Day.SATURDAY: 6 >, <Day.SUNDAY: 7 > ]
auto() 方法也可以可以自动检测字母.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 >>> from enum import Enum, auto>>> class CardinalDirection (Enum ):... def _generate_next_value_ (name, start, count, last_values ):... return name[0 ]... NORTH = auto()... SOUTH = auto()... EAST = auto()... WEST = auto()... >>> list (CardinalDirection)[ <CardinalDirection.NORTH: 'N' >, <CardinalDirection.SOUTH: 'S' >, <CardinalDirection.EAST: 'E' >, <CardinalDirection.WEST: 'W' > ]
使用别名和唯一值创建枚举类
你可以创建两个或多个成员具有相同常量值的枚举。冗余成员称为别名,在某些情况下可能很有用。例如,假设您有一个包含一组操作系统
(OS) 的枚举,如以下代码所示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 >>> from enum import Enum>>> class OperatingSystem (Enum ):... UBUNTU = "linux" ... MACOS = "darwin" ... WINDOWS = "win" ... DEBIAN = "linux" ... >>> >>> list (OperatingSystem)[ <OperatingSystem.UBUNTU: 'linux' >, <OperatingSystem.MACOS: 'darwin' >, <OperatingSystem.WINDOWS: 'win' > ] >>> >>> list (OperatingSystem.__members__.items())[ ('UBUNTU' , <OperatingSystem.UBUNTU: 'linux' >), ('MACOS' , <OperatingSystem.MACOS: 'darwin' >), ('WINDOWS' , <OperatingSystem.WINDOWS: 'win' >), ('DEBIAN' , <OperatingSystem.UBUNTU: 'linux' >) ]
前文提到可以使用@unique
装饰器来限制定义枚举.
这里是一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 >>> from enum import Enum, unique>>> @unique... class OperatingSystem (Enum ):... UBUNTU = "linux" ... MACOS = "darwin" ... WINDOWS = "win" ... DEBIAN = "linux" ... Traceback (most recent call last): ... ValueError: duplicate values in <enum 'OperatingSystem' >: DEBIAN -> UBUNTU
枚举的使用
访问枚举成员
常见的三种访问枚举成员的方法:
使用符号 .
引用方法: 使用 EnmuClass("key")
类似字典的访问方法: EnmuClass["key"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 >>> from enum import Enum>>> class CardinalDirection (Enum ):... NORTH = "N" ... SOUTH = "S" ... EAST = "E" ... WEST = "W" ... >>> >>> >>> >>> CardinalDirection.NORTH<CardinalDirection.NORTH: 'N' > >>> >>> CardinalDirection("N" )<CardinalDirection.NORTH: 'N' > >>> >>> CardinalDirection["NORTH" ]<CardinalDirection.NORTH: 'N' >
遍历枚举的成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 >>> for name in Flavor.__members__:... print (name)... VANILLA CHOCOLATE MINT >>> for name in Flavor.__members__.keys():... print (name)... VANILLA CHOCOLATE MINT >>> for member in Flavor.__members__.values():... print (member)... Flavor.VANILLA Flavor.CHOCOLATE Flavor.MINT >>> for name, member in Flavor.__members__.items():... print (name, "->" , member)... VANILLA -> Flavor.VANILLA CHOCOLATE -> Flavor.CHOCOLATE MINT -> Flavor.MINT
枚举中的比较
可以使用if
...elif
语句和match
...case
语句中使用枚举表明来比较枚举成员。默认情况下,枚举支持两种类型的比较运算符:
身份运算符 ,使用is
andis not
运算符
算数运算符 ,使用==
and!=
运算符
身份比较依赖于每个枚举成员都是其枚举类的单例实例这一事实.
is
此特性允许使用和运算符对成员进行快速且廉价的身份比较is not
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 >>> from enum import Enum>>> class AtlanticAveSemaphore (Enum ):... RED = 1 ... YELLOW = 2 ... GREEN = 3 ... PEDESTRIAN_RED = 1 ... PEDESTRIAN_GREEN = 3 >>> red = AtlanticAveSemaphore.RED>>> red == AtlanticAveSemaphore.REDTrue >>> red != AtlanticAveSemaphore.REDFalse >>> yellow = AtlanticAveSemaphore.YELLOW>>> yellow == redFalse >>> yellow is redFalse >>> yellow != redTrue >>> yellow is not redTrue >>> pedestrian_red = AtlanticAveSemaphore.PEDESTRIAN_RED>>> red == pedestrian_redTrue >>> red is pedestrian_redTrue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 >>> from enum import Enum>>> class Semaphore (Enum ):... RED = 1 ... YELLOW = 2 ... GREEN = 3 ... >>> def handle_semaphore (light ):... if light is Semaphore.RED:... print ("You must stop!" )... elif light is Semaphore.YELLOW:... print ("Light will change to red, be careful!" )... elif light is Semaphore.GREEN:... print ("You can continue!" )... >>> handle_semaphore(Semaphore.GREEN)You can continue ! >>> handle_semaphore(Semaphore.YELLOW)Light will change to red, be careful! >>> handle_semaphore(Semaphore.RED)You must stop!
枚举排序
默认情况下,Python
的枚举不支持比较运算符,如>
、<
、>=
和<=
.
这就是为什么您不能直接使用内置sorted()
函数对枚举成员进行排序的原因,如下例所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 >>> from enum import Enum>>> class Season (Enum ):... SPRING = 1 ... SUMMER = 2 ... AUTUMN = 3 ... WINTER = 4 ... >>> sorted (Season)Traceback (most recent call last): ... TypeError: '<' not supported between instances of 'Season' and 'Season'
来排序的时候,需要手动映射枚举成员为排序的 key 来进行排序.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> sorted (Season, key=lambda season: season.value)[ <Season.SPRING: 1 >, <Season.SUMMER: 2 >, <Season.AUTUMN: 3 >, <Season.WINTER: 4 > ] >>> sorted (Season, key=lambda season: season.name)[ <Season.AUTUMN: 3 >, <Season.SPRING: 1 >, <Season.SUMMER: 2 >, <Season.WINTER: 4 > ]
其他枚举类
构建整数枚举:IntEnum
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 >>> from enum import IntEnum>>> class Size (IntEnum ):... S = 1 ... M = 2 ... L = 3 ... XL = "4" ... >>> list (Size)[<Size.S: 1 >, <Size.M: 2 >, <Size.L: 3 >, <Size.XL: 4 >] >>> class Size (IntEnum ):... S = 1 ... M = 2 ... L = 3 ... XL = "4.o" ... Traceback (most recent call last): ... ValueError: invalid literal for int () with base 10 : '4.o'
使用 Flag
来构建枚举
使用 Flag
的好处之一就是可以让一个枚举类型包含另外几种类型.比如以下一个例子:
该枚举在给定的应用程序中包含一组用户角色。此枚举的成员包含整数值,您可以使用按位
OR 运算符 ( |
) 组合这些值。例如,名为 John
的用户同时具有USER
和SUPERVISOR
角色。请注意,存储在其中的对象john_roles
是您的Role
枚举的成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 >>> from enum import IntFlag>>> class Role (IntFlag ):... OWNER = 8 ... POWER_USER = 4 ... USER = 2 ... SUPERVISOR = 1 ... ADMIN = OWNER | POWER_USER | USER | SUPERVISOR... >>> john_roles = Role.USER | Role.SUPERVISOR>>> john_roles<Role.USER|SUPERVISOR: 3 > >>> type (john_roles)<enum 'Role' > >>> if Role.USER in john_roles:... print ("John, you're a user" )... John, you're a user >>> if Role.SUPERVISOR in john_roles: ... print("John, you' re a supervisor") ... John, you're a supervisor >>> Role.OWNER in Role.ADMIN True >>> Role.SUPERVISOR in Role.ADMIN True