深入了解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判断IP地址合法性的方法实例
Mar 13 Python
Python实现SVN的目录周期性备份实例
Jul 17 Python
python numpy函数中的linspace创建等差数列详解
Oct 13 Python
python读取txt文件并取其某一列数据的示例
Feb 19 Python
详解django2中关于时间处理策略
Mar 06 Python
用Anaconda安装本地python包的方法及路径问题(图文)
Jul 16 Python
Django Haystack 全文检索与关键词高亮的实现
Feb 17 Python
Python函数基本使用原理详解
Mar 19 Python
使用Django清空数据库并重新生成
Apr 03 Python
Django与pyecharts结合的实例代码
May 13 Python
Tensorflow全局设置可见GPU编号操作
Jun 30 Python
梳理总结Python开发中需要摒弃的18个坏习惯
Jan 22 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中的魔术方法总结和使用实例
2015/05/11 PHP
js 小贴士一星期合集
2010/04/07 Javascript
最短的javascript:地址栏载入脚本代码
2011/10/13 Javascript
JS方法调用括号的问题探讨
2014/01/24 Javascript
js查找节点的方法小结
2015/01/13 Javascript
javascript生成不重复的随机数
2015/07/17 Javascript
JS+CSS实现简单滑动门(滑动菜单)效果
2015/09/19 Javascript
vue.js通过路由实现经典的三栏布局实例代码
2018/07/08 Javascript
JavaScript常见JSON操作实例分析
2018/08/08 Javascript
jquery实现有过渡效果的tab切换
2020/07/17 jQuery
[01:41]DOTA2 2015国际邀请赛中国区预选赛第三日战报
2015/05/28 DOTA
[00:28]DOTA2北京网鱼队选拔赛
2015/04/08 DOTA
[22:59]VGJ.S vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
17个Python小技巧分享
2015/01/23 Python
python通过socket实现多个连接并实现ssh功能详解
2017/11/08 Python
疯狂上涨的Python 开发者应从2.x还是3.x着手?
2017/11/16 Python
Python验证文件是否可读写代码分享
2017/12/11 Python
在cmd中运行.py文件: python的操作步骤
2018/05/12 Python
判断python字典中key是否存在的两种方法
2018/08/10 Python
Python的UTC时间转换讲解
2019/02/26 Python
python3中类的继承以及self和super的区别详解
2019/06/26 Python
python 修改本地网络配置的方法
2019/08/14 Python
python实现文件批量编码转换及注意事项
2019/10/14 Python
Python之Numpy的超实用基础详细教程
2019/10/23 Python
python获取响应某个字段值的3种实现方法
2020/04/30 Python
python 发送get请求接口详解
2020/11/17 Python
HTML5标签嵌套规则详解【必看】
2016/04/26 HTML / CSS
美国乡村商店:Plow & Hearth
2016/09/12 全球购物
英国领先的电动可调床制造商:Laybrook
2019/12/26 全球购物
银行求职自荐书
2014/06/25 职场文书
民间借贷协议书范本
2014/10/01 职场文书
工厂仓管员岗位职责
2015/04/01 职场文书
电话营销开场白
2015/05/29 职场文书
团组织关系介绍信
2019/06/24 职场文书
2019职场实习报告该怎么写?
2019/07/01 职场文书
MySQL 数据库 增删查改、克隆、外键 等操作
2022/05/11 MySQL