一文读懂Python 枚举


Posted in Python onAugust 25, 2020

enum 是一组绑定到唯一常数值的符号名称,并且具备可迭代性和可比较性的特性。我们可以使用 enum 创建具有良好定义的标识符,而不是直接使用魔法字符串或整数,也便于开发工程师的代码维护。

创建枚举

我们可以使用 class 语法创建一个枚举类型,方便我们进行读写,另外,根据函数 API 的描述定义,我们可以创建一个 enum 的子类,如下:

from enum import Enum

class HttpStatus(Enum):
  OK = 200
  BAD_REQUEST = 400
  FORBIDDEN = 403
  NOT_FOUND = 404
  REQUEST_TIMEOUT = 408
  SERVICE_UNAVAILABLE = 500

注意: 枚举属性值可以是任何东西: int, str 等。如果确切的值不重要,您可以使用 auto 实例,并为您选择适当的值。如果您将 auto 与其他值混合,则必须小心。 枚举类型中,不可以设置相同名称的 name,可以有相同的 value。

enum 自带属性 namevalue,日常工作中使用最多的也是这两个属性,我们打印看看结果:

print('Member: {}'.format(HttpStatus.OK))        # Member: HttpStatus.OK
print('Member name: {}'.format(HttpStatus.OK.name))   # Member name: OK
print('Member value: {}'.format(HttpStatus.OK.value))  # Member value: 200
print(repr(HttpStatus.OK))               # <enum 'HttpStatus'>
print(type(HttpStatus.OK))               # <HttpStatus.OK: 200>
print(isinstance(HttpStatus.OK, HttpStatus))      # True

枚举迭代

枚举支持迭代和遍历顺序。举个例子:

from enum import Enum, auto

# 创建
class HttpStatus(Enum):
  OK = 200
  BAD_REQUEST = 400
  FORBIDDEN = 403
  NOT_FOUND = 404
  REQUEST_TIMEOUT = 408
  SERVICE_UNAVAILABLE = 500
  OTHER = auto.value

# 迭代
for status in HttpStatus:
  print('{} : {}'.format(status.name, status.value))

打印结果:

OK : 200
BAD_REQUEST : 400
FORBIDDEN : 403
NOT_FOUND : 404
REQUEST_TIMEOUT : 408
SERVICE_UNAVAILABLE : 500
OTHER : <object object at 0x000002863E1D7B10>

可以看出,遍历的每一个 status 是一个独立的枚举成员,拥有 namevalue 属性。

另外,我们也可以使用如下形式来进行枚举遍历:

for name, member in HttpStatus.__members__.items():
  print('{} : {}'.format(name, member))

枚举成员与属性访问

通过枚举 value 进行访问,访问需要使用元组()的形式

print(HttpStatus(200))   # HttpStatus.OK

通过枚举 name 进行访问,访问需要使用列表[]的形式

print(HttpStatus['OK'])   # HttpStatus.OK

将属性赋予另一个 enum 成员

number = HttpStatus.OK
print(number)        # HttpStatus.OK

枚举值唯一

上面我们创建的枚举类中,value 值是可以重复的,如果我们不想枚举类中的值重复可以是用装饰器 @unique,举例如下:

from enum import Enum, unique

# 创建
@unique
class HttpStatus(Enum):
  OK = 200
  BAD_REQUEST = 400
  FORBIDDEN = 403
  NOT_FOUND = 404
  REQUEST_TIMEOUT = 408
  SERVICE_UNAVAILABLE = 500
  OTHER = 200

我们运行后,报如下异常:

ValueError: duplicate values found in <enum 'HttpStatus'>: OTHER -> OK

我们查看源代码,发现加入此装饰器的枚举类型,unique 方法会将其 __members__.items() 进行遍历,追加到 duplicates 列表中,如果发现列表不为空,则抛出如上异常信息。

枚举自动赋值

此功能用于我们在使用枚举时,只在意枚举的标识符的含义而不在意值的情况下,但是如果需要与字符串或整数混合使用就要额外注意。下面贴上官方的示例:

import unittest
from enum import auto, Enum

class TestEnum(unittest.TestCase):
  
  def test_auto_number(self):
    class Color(Enum):
      red = auto()
      blue = auto()
      green = auto()
  
    self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
    self.assertEqual(Color.red.value, 1)
    self.assertEqual(Color.blue.value, 2)
    self.assertEqual(Color.green.value, 3)
  
  def test_auto_name(self):
    class Color(Enum):
      def _generate_next_value_(self, start, count, last):
        return self
  
      red = auto()
      blue = auto()
      green = auto()
  
    self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
    self.assertEqual(Color.red.value, 'red')
    self.assertEqual(Color.blue.value, 'blue')
    self.assertEqual(Color.green.value, 'green')

可以发现,使用 auto() 得到的是整数自增型,如果我们需要别的方式,只需要在我们的枚举类中,重写 _generate_next_value_ 方法。

枚举比较

枚举对象可以进行比较,但是不能进行值比较,如果需要进行值比较则需要枚举对象继承 IntEnum 对象,举个例子:

import unittest
from enum import Enum, IntEnum

class TestEnum(unittest.TestCase):
  class Season(IntEnum):
    SPRING = 1
    SUMMER = 2
    AUTUMN = 3
    WINTER = 4

  def test_comparisons(self):
    season = self.Season

    self.assertEqual(season.SPRING, 1)

    class Part(Enum):
      SPRING = 1
      CLIP = 2
      BARREL = 3
      
    self.assertNotEqual(Part.SPRING, 1)
    self.assertNotEqual(Part.SPRING, season.SPRING)

TestEnum().test_comparisons()

上面的测试例子当中,我们创建了两个继承类型不一样的枚举类,可以看到继承了 IntEnum Season 可以进行值的比较,而继承了 EnumPart 则不能进行值比较,并且 IntEnum 类型与 Enum 类型也不能进行比较,即使属性和值一样。

枚举方法

枚举中可以定义枚举类自身特有的方法,也可以复写一些已经在基类中定义好的方法,比如: __init__, __str__, __repr__ , __hash__ ,__format__ 等。举个例子:

from enum import Enum

class Mood(Enum):
  FUNKY = (1, "hello")
  HAPPY = (3, "world")

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

  def __init__(self, num, nice):
    self.num = num
    self.nice = nice

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

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

  @property
  def testValue(self):
    return self.nice + ':' + str(self.num)

上面我们定义了一个枚举类,其中 value 是一个枚举类型,我们可以定义 __init__ 方法去对应元组中的值,我们也复写了 __str__ 方法。

打印方法看看效果:

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

从输出结果看,我们自定义和复写的方法都已经成功的应用到了 Mood 类中。

枚举继承

不同于 java 中的枚举类, python 中的枚举类是可以被继承的,但是被继承的枚举类规定其不能定义任何成员,但可以定义抽象方法。举例如下:

class EnumExtend(unittest.TestCase):

  def test_extending(self):
    class Shade(Enum):
      def shade(self):
        print(self.name)

    class Color(Shade):
      red = 1
      green = 2
      blue = 3
    with self.assertRaises(TypeError):
      class MoreColor(Color):
        cyan = 4
        magenta = 5
        yellow = 6

  def test_extending2(self):
    class Shade(Enum):
      def shade(self):
        return self.name

    class Color(Shade):
      def hex(self):
        return '%s nice!' % self.value

    class MoreColor(Color):
      cyan = 4
      magenta = 5
      yellow = 6
    self.assertEqual(MoreColor.magenta.shade(), 'magenta')
    self.assertEqual(MoreColor.magenta.hex(), '5 nice!')

测试用例可以完美运行,我们可以发现:第一个方法中,抛出了 TypeError 的异常;第二个测试方法中,MoreColor 继承了 Color, Color 继承了 Shade, 并且我们可以通过子类调用父类中的方法。

总结

本节主要介绍了 enum 模块的基础知识,包含枚举的创建、枚举成员和属性的访问、枚举方法的创建、枚举的继承等。其中新版中的 _ignore_、_order_、_missing_ 等可以学习官网的例子,另外 enum 的子类 IntEnum、IntFlag等也是我们比较常用的枚举基类,本文中简单的介绍了 IntEnum, 而 IntFlag 相比与 IntEnum 多了 &, |, ^, ~ 的操作,其他的子类大家感兴趣也可以了解。

代码地址

示例代码:Python-100-days-day036

以上就是一文读懂Python 枚举的详细内容,更多关于Python 枚举的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python中装饰器的一个妙用
Feb 08 Python
Python脚本实现自动将数据库备份到 Dropbox
Feb 06 Python
python构建深度神经网络(续)
Mar 10 Python
在NumPy中创建空数组/矩阵的方法
Jun 15 Python
Python使用pyodbc访问数据库操作方法详解
Jul 05 Python
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题
Sep 27 Python
用python标准库difflib比较两份文件的异同详解
Nov 16 Python
Python实现的字典排序操作示例【按键名key与键值value排序】
Dec 21 Python
python getpass实现密文实例详解
Sep 24 Python
基于python实现数组格式参数加密计算
Apr 21 Python
简单且有用的Python数据分析和机器学习代码
Jul 02 Python
Python利用capstone实现反汇编
Apr 06 Python
详解python变量与数据类型
Aug 25 #Python
python获取百度热榜链接的实例方法
Aug 25 #Python
利用Python如何制作贪吃蛇及AI版贪吃蛇详解
Aug 24 #Python
python实现自动清理重复文件
Aug 24 #Python
anaconda3安装及jupyter环境配置全教程
Aug 24 #Python
Python+pyftpdlib实现局域网文件互传
Aug 24 #Python
实例代码讲解Python 线程池
Aug 24 #Python
You might like
如何对PHP程序中的常见漏洞进行攻击(下)
2006/10/09 PHP
PHP程序61条面向对象分析设计的经验小结
2008/11/12 PHP
基于php split()函数的用法详解
2013/06/05 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
2020/04/04 PHP
Array.prototype 的泛型应用分析
2010/04/30 Javascript
JS图片浏览组件PhotoLook的公开属性方法介绍和进阶实例代码
2010/11/09 Javascript
浅谈JSON中stringify 函数、toJosn函数和parse函数
2015/01/26 Javascript
JS动态修改表格cellPadding和cellSpacing的方法
2015/03/31 Javascript
关于iframe跨域POST提交的方法示例
2017/01/15 Javascript
基于JS代码实现简单易用的倒计时 x 天 x 时 x 分 x 秒效果
2017/07/13 Javascript
浅谈mint-ui 填坑之路
2017/11/06 Javascript
微信小程序授权登陆及每次检查是否授权实例代码
2019/09/18 Javascript
layui默认选中table的CheckBox复选框方法
2019/09/19 Javascript
使用TS来编写express服务器的方法步骤
2020/10/29 Javascript
[45:10]NB vs Liquid Supermajor小组赛 A组胜者组决赛 BO3 第二场 6.2
2018/06/04 DOTA
[01:04:20]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第一场 11.29
2020/12/02 DOTA
关于Python中空格字符串处理的技巧总结
2017/08/10 Python
Python3实现的Mysql数据库操作封装类
2018/06/06 Python
详解Django 中是否使用时区的区别
2018/06/14 Python
Python  Django 母版和继承解析
2019/08/09 Python
Python监控服务器实用工具psutil使用解析
2019/12/19 Python
python破解同事的压缩包密码
2020/10/14 Python
Django项目在pycharm新建的步骤方法
2021/03/02 Python
Html5 webview元素定位工具的实现
2020/08/07 HTML / CSS
彪马俄罗斯官网:PUMA俄罗斯
2019/07/13 全球购物
init进程的作用
2012/04/12 面试题
为什么要用EJB
2014/04/17 面试题
汉语专业应届生求职信
2013/10/01 职场文书
技术总监管理岗位职责
2014/03/09 职场文书
个人培训自我鉴定
2014/03/28 职场文书
六查六看个人剖析材料
2014/10/14 职场文书
幼儿园大班见习报告
2014/10/31 职场文书
努力工作保证书
2015/02/28 职场文书
2015年学校德育工作总结
2015/04/22 职场文书
网络舆情信息简报
2015/07/21 职场文书
PyTorch中的torch.cat简单介绍
2022/03/17 Python