中的枚举属性函数_enum 枚举(一)

本文介绍了Python的枚举Enum的创建、特性及使用方式,包括枚举的定义、枚举成员的访问、枚举成员的唯一性、别名处理以及枚举的继承规则。通过示例展示了枚举的迭代、枚举成员的获取以及如何查找枚举中的别名。同时,文章提及了枚举类的方法和限制,以及如何重载`__new__`函数。
摘要由CSDN通过智能技术生成

前情提示: 测试代码中,右尖括号(>)表示命令行中输入的命令;单独一行并以井字符(#)开头的为输出内容;库的导入仅在本文的第一个测试代码中展现,其他代码块均省略库的导入代码。

  • 系统类型: Windows 10

  • python 版本: Python 3.9.0

枚举是一组符号名称(枚举成员)的集合,枚举成员应该是唯一的、不可变的。

enum 模块将分为三个部分解析,第一部分主要介绍枚举的特性和 Enum 类,第二部分将介绍 Enum 类的三个变种类及相关要点,第三部分将介绍自定义枚举和一些零星的相关内容。

创建一个 Enum

枚举是使用 class 语法来创建的,这使得它们易于读写。但还是有一种以使用函数形式的创建方式,这个留到下文再讲,现在主要来说明一下使用 class 语法的创建方式。

import enum

上面的代码创建了一个枚举,class Test 是一个枚举,其中 Test 就是枚举对象的名称。

A = 1B = 'b' 这些等号两边的整体被称为 枚举成员,等号左边的被称为枚举成员的名称,枚举通常是用来表示常量的,所以枚举成员的名称一般使用大写形式。等号右边的被称为枚举成员的值,枚举成员的值可以是任意类型,如 intstr等等,只需要注意枚举成员的值在 枚举对象中是唯一的。

虽然创建枚举时使用了 class 语法,但是枚举与普通的 python 类不同,可以打印一些信息来进行对比:

'''枚举'''
class Test(enum.Enum):
A = 1

print(Test) # 打印枚举
#
print(Test.A) # 打印枚举成员本身
# Test.A
print(repr(Test.A)) # 打印枚举成员在解释器中的形式
#
print(type(Test.A)) # 打印枚举成员类型
#
print(isinstance(Test.A, Test)) # 判断枚举成员类型是否有枚举类型一致
# True

'''普通的 python 类'''
class Common:
A = 1

print(Common) # 打印类
#
print(Common.A) # 打印类属性的值
# 1
print(repr(Common.A)) # 打印类属性的值在解释器中的形式
# 1
print(type(Common.A)) # 打印类属性的值的类型
#
print(isinstance(Common.A, Test)) # 判断类属性的值的类型是否有类的类型一致
# False

首先,枚举创建出的对象自成一种类型,类型名就是枚举的名称(类名)。枚举的枚举成员(类的属性)被创建成了一个对象,并且类型就是所属枚举的类型。

枚举可以按照定义顺序进行迭代,并且枚举成员是不可变的,是可哈希的,因此字典中的键可以使用枚举成员。

class Test(enum.Enum):
A = 1

test_dict = {}
for i in Test:
test_dict[i] = 'value.' + str(i)
print(test_dict)
# {: 'value.Test.A', : 'value.Test.B', : 'value.Test.C'}
print(test_dict[Test.A])
# value.Test.A

那么怎么获取枚举成员呢,在枚举中有很多种访问方式:

class Test(enum.Enum):
A = 1

print(Test(1)) # 程序化访问
# Test.A
print(Test['A']) # 条目访问
# Test.A
print(Test.A.value) # 枚举成员的 value 属性
# 1
print(Test.A.name) # 枚举成员的 name 属性
# A

枚举中不允许有相同的枚举成员,但是允许枚举成员有同样的值,若查找的值有多个枚举成员,那么会按定义顺序返回第一个。

'''枚举成员有相同的名称'''
class Test(enum.Enum):
A = 1
A = 2
# TypeError: Attempted to reuse key: 'A'

'''枚举成员有相同的值'''
class Test(enum.Enum):
A = 1
B = 1

print(Test(1))
# Test.A

enum 模块中定义了一个装饰器 -- @enum.unique,可以强制规定枚举成员的值也必须是唯一的。

@enum.unique
class Test(enum.Enum):
A = 1
B = 1
# ValueError: duplicate values found in : B -> A

若枚举成员的值不重要或者其他不需要一一指定枚举成员的场景下,可以使用 enum.auto() 方法来替代输入的值。

class Test(enum.Enum):
A = enum.auto()
B = enum.auto()
C = 1

print(repr(Test.A))
#
print(repr(Test.B))
#
print(repr(Test.C))
#
print(list(Test))
# [, ]

当使用 enum.auto() 来定义枚举成员的值时,再次使用 int 类型的值时,最后得到的结果可能会和预想的不太一样。

enum.auto() 函数的返回值是由 _generate_next_value_() 函数决定的,默认情况下,此函数是根据最后一个 int 类型的枚举成员的值增加 1。此函数是可以重载的,重载时,方法定义必须在任何成员之前。

'''先定义一个值为 int 类型的枚举成员, 再使用 auto() 函数'''
class Test(enum.Enum):
A = 2
B = enum.auto()
C = enum.auto()
print(list(Test))
# [, , ]

'''定义一个值为非 int 类型的枚举成员, 再使用 auto() 函数'''
class Test(enum.Enum):
A = 'b'
B = enum.auto()
C = enum.auto()
print(list(Test))
# [, , ]

'''重载 _generate_next_value_()'''
class Test(enum.Enum):
def _generate_next_value_(name, start, count, last_values):
return name # 返回枚举成员的名字

A = enum.auto()
B = enum.auto()

print(list(Test))
# [, ]

在介绍 enum.auto() 函数时,测试示例中,枚举对象转换为 list 类型时少了一个枚举成员,这是因为少的那个枚举成员与之前的枚举成员的值是一样的,这个枚举成员被认为是一个别名,当对枚举成员迭代时,不会给出别名。

class Test(enum.Enum):
A = 1
B = 1
print(list(Test))
# []

而特殊属性 __members__是一个从名称到成员的只读有序映射。它包含枚举中所有的枚举成员,但是在迭代时,因为别名的原因,指向的枚举成员还是该值第一个定义的枚举成员。

class Test(enum.Enum):
A = 1
B = 1
print(dict(Test.__members__))
# {'A': , 'B': }

小栗子,找出枚举中所有的别名:

class Test(enum.Enum):
A = 1
B = 1
C = 2
D = 2
print([名称 for 名称, 枚举成员 in Test.__members__.items() if 枚举成员.name != 名称])
# ['B', 'D']

在枚举中,不仅仅只可以定义一些枚举成员,枚举也属于 python 的类,是可以拥有普通方法和特殊方法的,这里列举一个文档上的示例:

class Mood(enum.Enum):
FUNKY = 1
HAPPY = 3

def describe(self):
return self.name, self.value

def __str__(self):
return 'my custom str! {0}'.format(self.value)

@classmethod
def favorite_mood(cls):
return cls.HAPPY

print(Mood.favorite_mood())
# my custom str! 3
print(Mood.HAPPY.describe())
# ('HAPPY', 3)
print(str(Mood.FUNKY))
# my custom str! 1

但是枚举还是有一些限制,以单下划线开头和结尾的名称是由枚举保留而不可使用,例外项是包括特殊方法成员 (__str__()__add__() 等),描述符 (方法也属于描述符) 以及在 _ignore_ 中列出的变量名。

在介绍 _generate_next_value_() 函数时,为了重载这个函数,我们创建了一个基于 enum.Enum 的枚举,可以成为 枚举A,重载了 _generate_next_value_() 函数,然后又创建了一个基于 枚举A 的枚举。这样的定义是被允许的,在 enum 模块的规定下,一个新的 Enum 类必须基于一个 Enum 类,至多一个实体数据类型以及出于实际需要的任意多个基于 object 的 mixin 类。这些基类的顺序为:

class EnumName([mix-in, ...,] [data-type,] base-enum):
pass

另外,没有定义枚举成员的枚举才能被其他枚举继承,否则将会报错:

class A(enum.Enum):
AA = 1
class B(A):
BB = 2
# TypeError: B: cannot extend enumeration 'A'
参考资料

官方文档: https://docs.python.org/zh-cn/3/library/enum.html

源代码: Lib/enum.py

81a7a697481212d0e77f7b8f295efbcc.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值