Python(十一)枚举类

来源:互联网 发布:mac安装不了flash 编辑:程序博客网 时间:2024/05/29 19:36

枚举类的使用

实际开发中,我们离不开定义常量,当我们需要定义常量时,其中一个办法是用大写变量通过整数来定义,例如月份:

JAN = 1FEB = 2MAR = 3...NOV = 11DEC = 12

当然这样做简单快捷,缺点是类型是 int ,并且仍然是变量。

那有没有什么好的方法呢?

这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。正好 Python 提供了 Enum 类来实现这个功能如下:

# encoding=utf-8from enum import EnumMonth = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))# 遍历枚举类型for name, member in Month.__members__.items():    print(name, '---------', member, '----------', member.value)# 直接引用一个常量print('\n', Month.Jan)

输出结果如下:

Jan --------- Month.Jan ---------- 1Feb --------- Month.Feb ---------- 2Mar --------- Month.Mar ---------- 3Apr --------- Month.Apr ---------- 4May --------- Month.May ---------- 5Jun --------- Month.Jun ---------- 6Jul --------- Month.Jul ---------- 7Aug --------- Month.Aug ---------- 8Sep --------- Month.Sep ---------- 9Oct --------- Month.Oct ---------- 10Nov --------- Month.Nov ---------- 11Dec --------- Month.Dec ---------- 12 Month.Jan

可见,我们可以直接使用 Enum 来定义一个枚举类。上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 members 遍历它的所有成员的方法。注意的一点是 , member.value 是自动赋给成员的 int类型的常量,默认是从 1 开始的。而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改。

Enum 的源码

通过上面的实例可以知道通过 __members__ 可以遍历枚举类的所有成员。那为什么呢?

我们可以先来大致看看 Enum 的源码是如何实现的;Enum 在模块 enum.py 中,先来看看 Enum 类的片段

class Enum(metaclass=EnumMeta):    """Generic enumeration.    Derive from this class to define new enumerations.    """

可以看到,Enum 是继承元类 EnumMeta 的;再看看 EnumMeta 的相关片段

class EnumMeta(type):    """Metaclass for Enum"""    @property    def __members__(cls):        """Returns a mapping of member name->value.        This mapping lists all enum members, including aliases. Note that this        is a read-only view of the internal mapping.        """        return MappingProxyType(cls._member_map_)

首先 __members__方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 __members__(cls) 的访问方式改变为了变量的的形式,既可以直接通过__members__来进行访问了

自定义类型的枚举

但有些时候我们需要控制枚举的类型,那么我们可以 Enum 派生出自定义类来满足这种需要。通过修改上面的例子:

# encoding=utf-8from enum import Enum, uniqueEnum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))# @unique 装饰器可以帮助我们检查保证没有重复值@uniqueclass Month(Enum):    Jan = 'January'    Feb = 'February'    Mar = 'March'    Apr = 'April'    May = 'May'    Jun = 'June'    Jul = 'July'    Aug = 'August'    Sep = 'September '    Oct = 'October'    Nov = 'November'    Dec = 'December'if __name__ == '__main__':    print(Month.Jan, '----------',          Month.Jan.name, '----------', Month.Jan.value)    for name, member in Month.__members__.items():        print(name, '----------', member, '----------', member.value)

输出的结果如下:

Month.Jan ---------- Jan ---------- JanuaryJan ---------- Month.Jan ---------- JanuaryFeb ---------- Month.Feb ---------- FebruaryMar ---------- Month.Mar ---------- MarchApr ---------- Month.Apr ---------- AprilMay ---------- Month.May ---------- MayJun ---------- Month.Jun ---------- JuneJul ---------- Month.Jul ---------- JulyAug ---------- Month.Aug ---------- AugustSep ---------- Month.Sep ---------- SeptemberOct ---------- Month.Oct ---------- OctoberNov ---------- Month.Nov ---------- NovemberDec ---------- Month.Dec ---------- December

通过上面的例子,可以知道枚举模块定义了具有迭代 (interator) 和比较(comparison) 功能的枚举类型。 它可以用来为值创建明确定义的符号,而不是使用具体的整数或字符串。

枚举的比较

因为枚举成员不是有序的,所以它们只支持通过标识(identity) 和相等性 (equality) 进行比较。下面来看看 == 和 is 的使用:

# encoding=utf-8from enum import Enumclass User(Enum):    Twowater = 98    Liangdianshui = 30    Tom = 12Twowater = User.TwowaterLiangdianshui = User.Liangdianshuiprint(Twowater == Liangdianshui, Twowater == User.Twowater)print(Twowater is Liangdianshui, Twowater is User.Twowater)try:    print('\n'.join('  ' + s.name for s in sorted(User)))except TypeError as err:    print(' Error : {}'.format(err))

输出的结果:

False TrueFalse True Error : '<' not="" supported="" between="" instances="" of="" 'user'="" and="" 'user'<="" code="">

可以看看最后的输出结果,报了个异常,那是因为大于和小于比较运算符引发 TypeError 异常。也就是Enum类的枚举是不支持大小运算符的比较的。

那么能不能让枚举类进行大小的比较呢?

当然是可以的,使用 IntEnum 类进行枚举,就支持比较功能。

# encoding=utf-8import enumclass User(enum.IntEnum):    Twowater = 98    Liangdianshui = 30    Tom = 12try:    print('\n'.join(s.name for s in sorted(User)))except TypeError as err:    print(' Error : {}'.format(err))

看看输出的结果:

TomLiangdianshuiTwowater

通过输出的结果可以看到,枚举类的成员通过其值得大小进行了排序。也就是说可以进行大小的比较。

原文链接
本文转载只为技术交流,若侵权,请邮件至shuzhuchengfu@163.com联系我下架本文!

原创粉丝点击