Python enum的使用总结

Python enum的使用总结

枚举(enumeration)在许多编程语言中常被表示为一种基础的数据结构使用,枚举帮助组织一系列密切相关的成员到同一个群组机制下,一般各种离散的属性都可以用枚举的数据结构定义,比如颜色、季节、国家、时间单位等
在Python中没有内置的枚举方法,起初模仿实现枚举属性的方式是

class Directions:NORTH = 1EAST = 2SOUTH = 3WEST = 4

使用成员

Direction.EAST 
Direction.SOUTH 

检查成员

>>> print("North的类型:", type(Direction.NORTH))
>>> print(isinstance(Direction.EAST, Direction))
North的类型: <class 'int'>
False

成员NORTH的类型是int,而不是Direction,这个做法只是简单地将属性定义到类中

Python标准库enum实现了枚举属性的功能,接下来介绍enum的在实际工作生产中的用法

为什么要用enum,什么时候使用enum?

enum规定了一个有限集合的属性,限定只能使用集合内的值,明确地声明了哪些值是合法值,,如果输入不合法的值会引发错误,只要是想要从一个限定集合取值使用的方式就可以使用enum来组织值。

enum的定义/声明

from enum import Enumclass Directions(Enum):NORTH = 1EAST = 2SOUTH = 3WEST = 4

使用和类型检查:

>>> Directions.EAST
<Directions.EAST: 2>
>>> Directions.SOUTH
<Directions.SOUTH: 3>
>>> Directions.EAST.name
'EAST'
>>> Directions.EAST.value
2
>>> print("South的类型:", type(Directions.SOUTH))
South的类型: <enum 'Directions'>
>>> print(isinstance(Directions.EAST, Directions))
True
>>> 

检查示例South的的类型,结果如期望的是Directions。name和value是两个有用的附加属性。

实际工作中可能会这样使用

fetched_value = 2  # 获取值
if Directions(fetched_value) is Directions.NORTH:...
elif Directions(fetched_value) is Directions.EAST:...
else:...

输入未定义的值时:

>>> Directions(5)
ValueError: 5 is not a valid Directions

遍历成员

>>> for name, value in Directions.__members__.items():
...     print(name, value)
...
NORTH Directions.NORTH
EAST Directions.EAST
SOUTH Directions.SOUTH
WEST Directions.WEST

在继承Enum的类中定义方法

可以用于将定义的值转换为获取需要的值

from enum import Enumclass Directions(Enum):NORTH = 1EAST = 2SOUTH = 3WEST = 4def angle(self):right_angle = 90.0return right_angle * (self.value - 1)@staticmethoddef angle_interval(direction0, direction1):return abs(direction0.angle() - direction1.angle())
>>> east = Directions.EAST
>>> print("SOUTH Angle:", east.angle())
SOUTH Angle: 90.0
>>> west = Directions.WEST
>>> print("Angle Interval:", Directions.angle_interval(east, west))
Angle Interval: 180.0

将Enum类属性的值定义为函数或方法

from enum import Enum
from functools import partialdef plus_90(value):return Directions(value).angle + 90class Directions(Enum):NORTH = 1EAST = 2SOUTH = 3WEST = 4PLUS_90 = partial(plus_90)def __call__(self, *args, **kwargs):return self.value(*args, **kwargs)@propertydef angle(self):right_angle = 90.0return right_angle * (self.value - 1)print(Directions.NORTH.angle)
print(Directions.EAST.angle)
south = Directions(3)
print("SOUTH angle:", south.angle)
print("SOUTH angle plus 90: ", Directions.PLUS_90(south.value))

输出:

0.0
90.0
SOUTH angle: 180.0
SOUTH angle plus 90:  270.0

key: 1.将函数方法用partial包起来;2.定义__call__方法。

忽略大小写

class TimeUnit(Enum):MONTH = "MONTH"WEEK = "WEEK"DAY = "DAY"HOUR = "HOUR"MINUTE = "MINUTE"@classmethoddef _missing_(cls, value: str):for member in cls:if member.value == value.upper():return member
print(TimeUnit("MONTH"))
print(TimeUnit("Month"))

继承父类Enum的_missing_方法,在值的比较时将case改为一致即可
输出

TimeUnit.MONTH
TimeUnit.MONTH

自定义异常处理

第一种,执行SomeEnum(“abc”)时想要引发自定义错误,其中"abc"是未定义的属性值

class TimeUnit(Enum):MONTH = "MONTH"WEEK = "WEEK"DAY = "DAY"HOUR = "HOUR"MINUTE = "MINUTE"@classmethoddef _missing_(cls, value: str):raise Exception("Customized exception")print(TimeUnit("MONTH"))
TimeUnit("abc")

输出

TimeUnit.MONTHValueError: 'abc' is not a valid TimeUnit
...
Exception: Customized exception

第二种,执行SomeEnum.__getattr__(“ABC”)时,想要引发自定义错误,其中"ABC"是未定义的属性名称,需要重写一下EnumMeta中的__getattr__方法,然后指定实例Enum对象的的metaclass

from enum import Enum, EnumMeta
from functools import partialclass SomeEnumMeta(EnumMeta):def __getattr__(cls, name: str):value = cls.__members__.get(name.upper())   # (这里name是属性名称,可以自定义固定传入大写(或小写),对应下面的A1是大写)if not value:raise Exception("Customized exception")return valueclass SomeEnum1(Enum, metaclass=SomeEnumMeta):A1 = "123"class SomeEnum2(Enum, metaclass=SomeEnumMeta):A1 = partial(lambda x: x)def __call__(self, *args, **kwargs):return self.value(*args, **kwargs)print(SomeEnum1.__getattr__("A1"))
print(SomeEnum2.__getattr__("a1")("123"))
print(SomeEnum2.__getattr__("B")("123"))

输出

SomeEnum1.A1123...
Exception: Customized exception

第二种如果成员找不到时不需要自定义的报错也有一种简单的方法,即直接使用__getitem__方法:

class SomeEnum(CaseInsensitiveEnum):A1 = partial(lambda x: x)def __call__(self, *args, **kwargs):return self.value(*args, **kwargs)if __name__ == '__main__':s = SomeEnum.__getitem__("A1")print(s("a"))      

输出

a

enum的进阶用法

Functional APIs
动态创建和修改Enum对象,可以在不修改原定义好的Enum类的情况下,追加修改,这里借用一个说明示例,具体的场景使用案例可以看下面的场景举例

>>> # Create an Enum class using the functional API
... DirectionFunctional = Enum("DirectionFunctional", "NORTH EAST SOUTH WEST", module=__name__)
... # Check what the Enum class is
... print(DirectionFunctional)
... # Check the items
... print(list(DirectionFunctional))
... print(DirectionFunctional.__members__.items())
... 
<enum 'DirectionFunctional'>
[<DirectionFunctional.NORTH: 1>, <DirectionFunctional.EAST: 2>, <DirectionFunctional.SOUTH: 3>, <DirectionFunctional.WEST: 4>]
dict_items([('NORTH', <DirectionFunctional.NORTH: 1>), ('EAST', <DirectionFunctional.EAST: 2>), ('SOUTH', <DirectionFunctional.SOUTH: 3>), ('WEST', <DirectionFunctional.WEST: 4>)])
>>> # Create a function and patch it to the DirectionFunctional class
... def angle(DirectionFunctional):
...     right_angle = 90.0
...     return right_angle * (DirectionFunctional.value - 1)
... 
... 
... DirectionFunctional.angle = angle
... 
... # Create a member and access its angle
... south = DirectionFunctional.SOUTH
... print("South Angle:", south.angle())
... 
South Angle: 180.0

注:这里没有使用类直接声明的方式来执行枚举(定义时如果不指定值默认是从1开始的数字,也就相当于NORTH = auto(),auto是enum中的方法),仍然可以在后面为这个动态创建的DirectionFunctional创建方法,这种在运行的过程中修改对象的方法也就是python的monkey patching。

Functional APIs的用处和使用场景举例:

在不修改某定义好的Enum类的代码块的情况下,下面示例中是Arithmethic类,可以认为是某源码库我们不想修改它,然后增加这个Enum类的属性,有两种方法:
1.enum.Enum对象的属性不可以直接被修改,但我们可以动态创建一个新的Enum类,以拓展原来的Enum对象
例如要为下面的Enum对象Arithmetic增加一个取模成员MOD="%",但是又不能修改Arithmetic类中的代码块:

# enum_test.py
from enum import Enumclass Arithmetic(Enum):ADD = "+"SUB = "-"MUL = "*"DIV = "/"

就可以使用enum的Functional APIs方法:

# functional_api_test.py
from enum import EnumDynamicEnum = Enum("Arithmetic", {"MOD": "%"}, module="enum_test", qualname="enum_test.Arithmetic")print(DynamicEnum.MOD)print(eval(f"5 {DynamicEnum.MOD.value} 3"))

输出:

Arithmetic.MOD
2

注意:动态创建Enum对象时,要指定原Enum类所在的module名称: "Yourmodule",否则执行时可能会因为找不到源无法解析,qualname要指定类的位置:"Yourmodule.YourEnum",值用字符串类型

2.使用aenum.extend_enum可以动态修改enum.Enum对象
为enum.Enum类Arithmetic增加一个指数成员EXP="**",且不修改原来的Arithmetic类的代码块:

# functional_api_test.py
from aenum import extend_enum
from enum_test import Arithmeticextend_enum(Arithmetic, "EXP", "**")
print(Arithmetic, list(Arithmetic))
print(eval(f"2 {Arithmetic.EXP.value} 3"))

输出

<enum 'Arithmetic'> [<Arithmetic.ADD: '+'>, <Arithmetic.SUB: '-'>, <Arithmetic.MUL: '*'>, <Arithmetic.DIV: '/'>, <Arithmetic.EXP: '**'>]
8

参考:https://betterprogramming.pub/take-advantage-of-the-enum-class-to-implement-enumerations-in-python-1b65b530e1d
https://docs.python.org/3/library/enum.html
https://stackoverflow.com/questions/28126314/adding-members-to-python-enums

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ascii码转字符

在C语言中&#xff0c;ASCII码转字符非常简单。但是之前因为没有用到就没有去关注这方面的问题。 printf("%c\n",char(69)); E 下面是ASCII码表&#xff1a; BinDecHex缩写/字符解释0000 0000000NUL(null)空字符0000 0001101SOH(start of headline)标题开始0000…

SCI论文写作训练营笔记汇总01_概述+文献检索与管理

1 概述 1.1 适用人群 ①初涉科研&#xff0c; 目前或将来有英文科技论文发表需求的科研工作者 ②正在撰写或准备撰写英文科技论文的科研工作者 1.2 科技论文的基本结构 1.3 科技论文组成部分的写作方法 1.4 阅读文献的重要性 2、文献检索与管理 2.1 如何查找文献参考 2.2 文…

天猫11.11:搜索引擎实时秒级更新(转载)

搜索是很多用户在天猫购物时的第一入口&#xff0c;搜索结果会根据销量、库存、人气对商品进行排序&#xff0c;而商品的显示顺序往往会决定用户的选择&#xff0c;所以保证搜索结果的实时性和准确性非常重要。在电商系统中&#xff0c;特别是在“双十一”这样的高并发场景下&a…

pandas处理日期的几种常用方法

1.读取字符串日期 写入csv 文件 csv_text """date, value 2022-01-01, 1 2022-01-05, 5 2022-11-05, 5 """ with open("date_text.csv", "w") as f:f.write(csv_text)读取日期 df pd.read_csv("date_text.csv"…

OAD 空中升级

http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/p/69222/172351.aspx#172351&#xfeff;&#xfeff;第二十三节 OAD空中升级 通过仿真器更新程序或者通过USB更新固件那都是一般人都可以实现的操作&#xff0c;但是要想实现OAD空中升级…

SCI论文写作训练营笔记汇总02_英文科技论文阅读与解析

3、英文科技论文阅读与解析的方法 3.1 科技论文介绍 3.1.1 科技论文的类型 • Research • Review • Theoretical • Methodological • Case study 3.1.2 研究型论文的结构 3.1.3 科技论文的基本结构 3.2 文献阅读 3.2.1 文献选择的原则 3.2.2 文献阅读顺序 3.2.2 文献阅读…

9.带有返回值的函数

<!DOCTYPE html><html><body> <p>本例调用的函数会执行一个计算&#xff0c;然后返回结果&#xff1a;</p> <p id"demo"></p> <script>function myFunction(a,b){return a*b;} document.getElementById("demo&…

报错curl: (7) Failed to connect to 127.0.0.1 port xxxx: Connection refused

&#xff08;pyenv install xxx&#xff09; 报错curl: (7) Failed to connect to 127.0.0.1 port xxxx: Connection refused的解决方法 问题重现截图&#xff1a; 在查看下面的原因和使用解决方法之前&#xff0c;确保自己的pyenv已经安装好了最新的python-build&#xff0c…

linux通过I2C地址查看设备名称

 root@android:/sys/bus/i2c # cd devices cd devices root@android:/sys/bus/i2c/devices # ls ls 0-0020 0-0022 0-0036 0-0078 1-000c 1-000d 1-001d 1-0028 1-0029 1-002a 1-0038 1-0060 1-0068 2-001c i2c-0 i2c-1 i2c-2 root@android:/sys/bus/i2c/devices # cd 0-00…

SCI论文写作训练营笔记汇总03_科技论文写作(方法篇)

4、科技论文写作——方法篇 4.1 准备工作与概述 4.1.2 杂志编辑评估文章的标准 4.2 图表部分的写作方法 4.2.1 为什么使用图表 4.2.2 如何使用图表 4.2.3 如何选择图or表or文字 4.2.4 图片/表格制作软件 4.2.5 图片的各种指标 4.2.6 图片的分类 4.2.6 图注的使用 4.2.7 表格 …

跨域获取

本地&#xff1a; <?php$_arr array(a>1,b>2,c>3);$_result json_encode($_arr);echo $_result; ?> //本地获取$(form input[typebutton]).click(function(){$.ajax({type:"post",url:"test.php",async:true,dataType:json,success:fun…

python 嵌套型partials(nested partials)的使用

Python嵌套型partial的使用 partial对象中包含partial对象的使用 要实现的目标&#xff0c;简单示例&#xff1a; from functools import partialdef func1(f):return fdef func2(f1):return f1def func(n):return np partial(func2, partial(func1, partial(func, 5))) pri…

SCI论文写作训练营笔记汇总04_科技论文写作(技巧篇)

1、语言点 1.1 时态 1.1.1 时态使用的基本原则 1.1.2 在引言部分的时态使用 1.1.3 在“材料与方法”部分的时态使用 1.1.4 在“结果”部分的时态使用 1.1.5 在“讨论”部分的时态使用 1.1.6 总结 1.2 语态 1.2.1 语态-主动/被动 1.2.2 语态-主动/被动的不同点 1.2.2 语态-主…

做怎样的一个自己

1、如果总是患得患失&#xff0c;即使一时的成功&#xff0c;也不可能找到正确的自己。 2、这一次的创业机会错失了&#xff0c;是一件非常遗憾的事。 3、可是我会是更好的我&#xff0c;明天的我会是更加优秀的我&#xff0c;我将要遇见那个超过自己我我。 为自己努力&#…

SCI论文写作训练营笔记汇总05_英文论文投稿流程与常见问题(完)

1 目标期刊的选择 1.1 文章未送审直接被拒稿的常见理由 1.2 目标期刊的选择 1.2.1 学科与影响力 1.2.2 影响因子 1.2.3 审稿平均周期 1.2.4 主编水平 1.2.5 版面费 2 根据期刊要求调整文章 2.1 具体 2.2 期刊的审查重点 2.3 期刊的审查列表 3 其他材料 3.1 稿件作者信息 3.…

【bzoj1738】[Usaco2005 mar]Ombrophobic Bovines 发抖的牛 Floyd+二分+网络流最大流

题目描述 FJs cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They have decided to put a rain siren on the farm to let them know when rain is approaching. They intend to create a rai…

动态规划思路和Python解决零钱兑换问题和最大乘积子序列的乘积的问题

动态规划&#xff08;Dynamic Programming&#xff09;思路和Python解题示例 动态规划是一种主要用来优化朴素递归的方法&#xff0c;每当输入不同值调用递归函数出现大量重复的&#xff08;子&#xff09;输入和调用&#xff08;返回结果&#xff09;时&#xff0c;就可以考虑…

open(/dev/ietctl, O_RDWR) 参数含义

这是文件I/O的常用函数&#xff0c;open函数&#xff0c;open函数用来打开一个设备&#xff0c;他返回的是一个整型变量&#xff0c;如果这个值等于-1&#xff0c;说明打开文件出现错误&#xff0c;如果为大于0的值&#xff0c;那么这个值代表的就是文件描述符。一般的写法是if…

【Pytorch神经网络实战案例】06 逻辑回归拟合二维数据

1 逻辑回归与拟合过程 1.1 准备数据-code_01_moons.py&#xff08;第1部分&#xff09; import sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,plot_losses,predict,plot_decision_boundary# 1.1 准…

将Win10包含中文的用户名改为英文的,同时解决Anaconda navigator无法运行jupyter的问题

Win10用户名包含中文字符导致无法在Anaconda navigator直接运行jupyter的问题 本篇文章内容包含&#xff1a; WIN10如何修改"C:\Users\用户名"中的用户名执行1后&#xff0c;也就是用户名修改为英文名后&#xff0c;在Anaconda navigator启动之前无法启动的jupyter…