Python, 写一个简单的属于自己的BaseEnum类
Why do This
枚举, 作为管理常量的有效手段之一, 在各大主流语言中都有对应的语言级别的语法. 但是在 Python 中没有这个语法, 一般来说, 大家比较倾向使用module 级别的常量来处理, 这种做法, 自然既简单又粗暴又有效. 但是如果需要管理大量常量, 在常见的业务系统中, 这个特别常见, 仅仅使用上面的三板斧是有点不够的.
来看看 Python 3 标准库的 enum. 嘴上说不要, 心里确实很诚实, Python 总算是将其加入到语言中了, 虽然是以一种库的形式. 首先我们来看看其使用方式:importenum
classDirectionEnum(enum.IntEnum):
"""直接继承 IntEnum, 这是很常见的需求"""
UP=1
DOWN=2
LEFT=3
RIGHT=4
classDirectionEnum2(enum.Enum):
"""
继承更加底层的 Enum 类
让自己的实现更加灵活
"""UP='UP'DOWN='DOWN'LEFT='LEFT'RIGHT='RIGHT'if__name__=='__main__':
somevalue=1
# 1. 第一种使用方式, OK, 很符合我们的使用习惯, 并且是 work 的
ifsomevalue==DirectionEnum.UP:
# 会运行, 猜测是, IntEnum 内部做了一定的拆包动作
print('yes')
somevalue2='UP'
# 2. 第一种使用方式, OK, 很符合我们的使用习惯, 然而得到的, 却不是正确结果
ifsomevalue2==DirectionEnum2.UP:
# 不会运行, 没有使用 .value
print('yes2')
# 3. 第三种使用方式, OK, 并不是非常符合我们的习惯, 但是, 得到的预期结果是正确的
ifsomevalue2==DirectionEnum2.UP.value:
# 运行, 使用了 .value
print('yes2')
从上面我们可以看到, 如果仅仅是一些 int 类型的枚举集合, 那么使用 IntEnum 是 OK 的. 如果枚举集合的成分比较复杂, 那么就要使用 Enum, 虽然可以得到预期的正确结果, 但是却要改改自己的使用习惯, 强迫自己打出
DirectionEnum2.UP.value
这样的组合.
然而, 作为脑瓜子不好使的人来说,
DirectionEnum2.UP.value
这种我很难记住, 而且也不符合我的直觉啊, 另外, 我的大部分场景, 只是需要安安静静地使用一个枚举而已, 看 enum 库的内部实现, 又是元类, 又是委托啥的, 各种高科技都用上了. 所以, 我们就有强大的动力, 去适应自己, 而不是适应别人.
How to do
考虑到我们的使用场景非常单一 & 简单, 所以就想到了如下实现importfunctools
classBaseEnum:
@classmethod
@functools.lru_cache(maxsize=1024)
defvalues(cls):
d=cls.__dict__
return[v
fork,vind.items()
if(notk.startswith('_'))andk.isupper()]
然后使用之, 这里我们通过写 UT 的形式去学习使用接口:fromunittestimportTestCase
importpy3utils
classDirectionEnum(py3utils.BaseEnum):
UP=1
DOWN=2
LEFT=3
RIGHT=4
classTestBaseEnum(TestCase):
deftest_values_is_list(self):
self.assertTrue(isinstance(DirectionEnum.values(),list))
deftest_values(self):
e=[1,2,3,4]
actual=DirectionEnum.values()
self.assertEqual(e,actual)
deftest_enum(self):
actual=DirectionEnum.UP
expected=1
self.assertEqual(actual,expected)
Finally
一些平时使用得比较趁手得代码 snippet, 最好积累起来, 放入自己特定得代码仓库中, 以后想起来了, 直接复用之即可. 比如我, 就将上面得 snippets 加入到自己的仓库中
https://github.com/hezhiming/py3utils
, 并佐以比较完善的的 UT, 以备不时之需.:)
来源: https://juejin.im/post/5b2a6d4351882574a6724c5b