一文读懂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 队列详解及实例代码
Oct 18 Python
通过Python爬虫代理IP快速增加博客阅读量
Dec 14 Python
使用Windows批处理和WMI设置Python的环境变量方法
Aug 14 Python
Python3 requests文件下载 期间显示文件信息和下载进度代码实例
Aug 16 Python
Python 使用指定的网卡发送HTTP请求的实例
Aug 21 Python
python操作gitlab API过程解析
Dec 27 Python
Python3监控windows,linux系统的CPU、硬盘、内存使用率和各个端口的开启情况详细代码实例
Mar 18 Python
Python Scrapy框架:通用爬虫之CrawlSpider用法简单示例
Apr 11 Python
Python生成并下载文件后端代码实例
Aug 31 Python
利用django创建一个简易的博客网站的示例
Sep 29 Python
Django用户认证系统如何实现自定义
Nov 12 Python
关于python scrapy中添加cookie踩坑记录
Nov 17 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 方便水印和缩略图的图形类
2009/05/21 PHP
php5.5新数组函数array_column使用
2013/07/08 PHP
Yii2 批量插入、更新数据实例
2017/03/15 PHP
phpstorm 正则匹配删除空行、注释行(替换注释行为空行)
2018/01/21 PHP
js 判断计算字符串长度/判断空的简单方法
2013/08/05 Javascript
jQuery实现首页顶部可伸缩广告特效代码
2015/04/15 Javascript
jquery ajax结合thinkphp的getjson实现跨域的方法
2016/06/06 Javascript
Bootstrap基本插件学习笔记之轮播幻灯片(23)
2016/12/08 Javascript
js仿搜狐视频记录片列表展示效果
2020/05/30 Javascript
JS实现的走迷宫小游戏完整实例
2017/07/19 Javascript
通过jQuery学习js类型判断的技巧
2019/05/27 jQuery
[02:43]2014DOTA2国际邀请赛 官方Alliance战队纪录片
2014/07/14 DOTA
Python高效编程技巧
2013/01/07 Python
用python登录Dr.com思路以及代码分享
2014/06/25 Python
在Python的Django框架上部署ORM库的教程
2015/04/20 Python
Python运算符重载详解及实例代码
2017/03/07 Python
python利用dir函数查看类中所有成员函数示例代码
2017/09/08 Python
python书籍信息爬虫实例
2018/03/19 Python
对python numpy数组中冒号的使用方法详解
2018/04/17 Python
Python理解递归的方法总结
2019/01/28 Python
python多继承(钻石继承)问题和解决方法简单示例
2019/10/21 Python
python的Jenkins接口调用方式
2020/05/12 Python
python将logging模块封装成单独模块并实现动态切换Level方式
2020/05/12 Python
Java里面如何创建一个内部类的实例
2015/01/19 面试题
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
酒店公关部经理岗位职责
2013/11/24 职场文书
公司年会演讲稿范文
2014/01/11 职场文书
幼儿教师考核制度
2014/01/25 职场文书
付款委托书范本
2014/10/05 职场文书
2015个人半年总结范文
2015/03/09 职场文书
2015年幼儿园学期工作总结
2015/05/22 职场文书
2016年记者节感言
2015/12/08 职场文书
2019个人工作总结
2019/06/21 职场文书
详解CSS伪元素的妙用单标签之美
2021/05/25 HTML / CSS
MySQL优化之慢日志查询
2022/06/10 MySQL
win10滚动条自动往上跑怎么办?win10滚动条自动往上跑的解决方法
2022/08/05 数码科技