深入了解Python枚举类型的相关知识


Posted in Python onJuly 09, 2019

枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期、月份、状态等。

Python 的原生类型(Built-in types)里并没有专门的枚举类型,但是我们可以通过很多方法来实现它,例如字典、类等:

MiracleLove = {'MON': '林志玲', 'TUS': '陈意涵', 'WEN': '张柏芝', 'THU': '辛芷蕾', 'FRI': '周冬雨'}

class MiracleLove:
  MON = '林志玲'
  TUS = '陈意涵'
  WEN = '张柏芝'
  THU = '辛芷蕾'
  FRI = '周冬雨'

上面两种方法可以看做是简单的枚举类型的实现。

如果只在局部范围内用到了这样的枚举变量是没有问题的。

但问题在于它们都是可变的(mutable),也就是说可以在其它地方被修改从而影响其正常使用:

MiracleLove['MON'] = MiracleLove['FRI']
print(MiracleLove)

通过类定义的枚举甚至可以实例化,变得不伦不类:

ml = MiracleLove()
print(ml.MON)

MiracleLove.MON = 2
print(ml.MON)

当然也可以使用不可变类型(immutable),例如元组,但是这样就失去了枚举类型的本意,将标签退化为无意义的变量:

MiracleLove = ('R', 'G', 'B')
print(MiracleLove[0], MiracleLove[1], MiracleLove[2])

为了提供更好的解决方案,Python 通过 PEP 435 在 3.4 版本中添加了 enum 标准库,3.4 之前的版本也可以通过 pip install enum 下载兼容支持的库。

enum 提供了 Enum/IntEnum/unique 三个工具,用法也非常简单,可以通过继承 Enum/IntEnum 定义枚举类型,其中 IntEnum 限定枚举成员必须为(或可以转化为)整数类型,而 unique 方法可以作为修饰器限定枚举成员的值不可重复:

from enum import Enum, IntEnum, unique

try:
  @unique
  class MiracleLove(Enum):
    MON = '林志玲'
    TUS = '陈意涵'
    WEN = '张柏芝'
    THU = '辛芷蕾'
    FRI = '周冬雨'
except ValueError as e:
  print(e)
  
# duplicate values found in <enum 'MiracleLove'>: FRI -> MON
try:
  class MiracleLove(IntEnum):
    MON = 1
    TUS = 2
    WEN = 3
    THU = 4
    FRI = '周冬雨'
except ValueError as e:
  print(e)

# invalid literal for int() with base 10: '周冬雨'

更有趣的是 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改:

class MiracleLove(Enum):
  MON = '林志玲'
  TUS = '陈意涵'
  WEN = '张柏芝'
  THU = '辛芷蕾'
  FRI = '周冬雨'

try:
  MiracleLove.MON = 2
except AttributeError as e:
  print(e)

# Cannot reassign members.

虽然不可实例化,但可以将枚举成员赋值给变量:

mon = MiracleLove(0)
tus = MiracleLove(1)
wen = MiracleLove(2)
print(mon, tus, wen)

# MiracleLove.MON 
# MiracleLove.TUS 
# MiracleLove.WEN

也可以进行比较判断:

print(mon is MiracleLove.MON)
print(mon == MiracleLove.MON)
print(mon is tus)
print(wen != MiracleLove.TUS)
print(mon == 0) # 不等于任何非本枚举类的值

# True
# True
# False
# True
# False

最后一点,由于枚举成员本身也是枚举类型,因此也可以通过枚举成员找到其它成员:

print(mon.TUS)
print(mon.TUS.WEN.MON)

# MiracleLove.TUS
# MiracleLove.MON

但是要谨慎使用这一特性,因为可能与成员原有的命名空间中的名称相冲突:

print(mon.name, ':', mon.value)
class Attr(Enum):
  name = 'NAME'
  value = 'VALUE'

print(Attr.name.value, Attr.value.name)

# R : 0
# NAME value

总结:

enum 模块的用法很简单,功能也很明确,但是其实现方式却非常值得学习。如果你想更深入了解更多 Python 中关于 Class 和 Metaclass 的黑魔法,又不知道如何入手,那么不妨阅读一下 enum 的源码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
从Python的源码来解析Python下的freeblock
May 11 Python
python实现将文本转换成语音的方法
May 28 Python
python运行时间的几种方法
Jun 17 Python
Python极简代码实现杨辉三角示例代码
Nov 15 Python
python3设计模式之简单工厂模式
Oct 17 Python
Python编程scoketServer实现多线程同步实例代码
Jan 29 Python
python删除服务器文件代码示例
Feb 09 Python
tensorflow实现softma识别MNIST
Mar 12 Python
python将txt文档每行内容循环插入数据库的方法
Dec 28 Python
基于Python绘制美观动态圆环图、饼图
Jun 03 Python
使用keras时input_shape的维度表示问题说明
Jun 29 Python
详解如何使用Pytest进行自动化测试
Jan 14 Python
Python 的AES加密与解密实现
Jul 09 #Python
python+numpy按行求一个二维数组的最大值方法
Jul 09 #Python
使用Python轻松完成垃圾分类(基于图像识别)
Jul 09 #Python
Python分析彩票记录并预测中奖号码过程详解
Jul 09 #Python
python求最大值,不使用内置函数的实现方法
Jul 09 #Python
pandas的连接函数concat()函数的具体使用方法
Jul 09 #Python
python爬虫的一个常见简单js反爬详解
Jul 09 #Python
You might like
php的ajax框架xajax入门与试用介绍
2010/12/19 PHP
php使用simplexml_load_file加载XML文件并显示XML的方法
2015/03/19 PHP
php使用NumberFormatter格式化货币的方法
2015/03/21 PHP
ThinkPHP打水印及设置水印位置的方法
2016/10/14 PHP
php操作mongodb封装类与用法实例
2018/09/01 PHP
(jQuery,mootools,dojo)使用适合自己的编程别名命名
2010/09/14 Javascript
sencha touch 模仿tabpanel导航栏TabBar的实例代码
2013/10/24 Javascript
JS控制图片翻转示例代码(兼容firefox,ie,chrome)
2013/12/19 Javascript
将页面table内容与样式另存成excel文件的方法
2015/08/05 Javascript
Google 地图叠加层实例讲解
2016/08/06 Javascript
网页挂马方式整理及详细介绍
2016/11/03 Javascript
jQuery 的 ready()的纯js替代方法
2016/11/20 Javascript
JavaScript生成.xls文件的代码
2016/12/22 Javascript
浅谈Vue.js中的v-on(事件处理)
2017/09/05 Javascript
微信小程序tabbar底部导航
2018/11/05 Javascript
Javascript异步执行不按顺序解决方案
2020/04/30 Javascript
让IDE识别webpack的别名alias的实现方法
2020/05/06 Javascript
vue实现几秒后跳转新页面代码
2020/09/09 Javascript
vue+Element-ui实现登录注册表单
2020/11/17 Javascript
[03:47]2015国际邀请赛第三日现场精彩回顾
2015/08/08 DOTA
python使用KNN算法手写体识别
2018/02/01 Python
python如何通过twisted实现数据库异步插入
2018/03/20 Python
PyQt5每天必学之事件与信号
2018/04/20 Python
解决Python下json.loads()中文字符出错的问题
2018/12/19 Python
Python将视频或者动态图gif逐帧保存为图片的方法
2019/09/10 Python
Tensorflow中k.gradients()和tf.stop_gradient()用法说明
2020/06/10 Python
Python 如何测试文件是否存在
2020/07/31 Python
浅谈matplotlib默认字体设置探索
2021/02/03 Python
获取邓白氏信用报告:Dun & Bradstreet
2019/01/22 全球购物
美国家居装饰店:Pier 1
2019/09/04 全球购物
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
求职信模版
2013/11/30 职场文书
公务员综合考察材料
2014/02/01 职场文书
大学生优秀班干部事迹材料
2014/05/26 职场文书
毕业论文指导教师评语
2014/12/30 职场文书
Nginx配置根据url参数重定向
2022/04/11 Servers