Why do This
枚举, 作为管理常量的有效手段之一, 在各大主流语言中都有对应的语言级别的语法. 但是在 Python 中没有这个语法, 一般来说, 大家比较倾向使用module 级别的常量来处理, 这种做法, 自然既简单又粗暴又有效. 但是如果需要管理大量常量, 在常见的业务系统中, 这个特别常见, 仅仅使用上面的三板斧是有点不够的.
来看看 Python 3 标准库的 enum. 嘴上说不要, 心里确实很诚实, Python 总算是将其加入到语言中了, 虽然是以一种库的形式. 首先我们来看看其使用方式:
- import enum
- class DirectionEnum(enum.IntEnum):
- """直接继承 IntEnum, 这是很常见的需求"""
- UP = 1
- DOWN = 2
- LEFT = 3
- RIGHT = 4
- class DirectionEnum2(enum.Enum):
- """
- 继承更加底层的 Enum 类
- 让自己的实现更加灵活
- """UP ='UP'DOWN ='DOWN'LEFT ='LEFT'RIGHT ='RIGHT'if __name__ =='__main__':
- somevalue = 1
- # 1. 第一种使用方式, OK, 很符合我们的使用习惯, 并且是 work 的
- if somevalue == DirectionEnum.UP:
- # 会运行, 猜测是, IntEnum 内部做了一定的拆包动作
- print('yes')
- somevalue2 = 'UP'
- # 2. 第一种使用方式, OK, 很符合我们的使用习惯, 然而得到的, 却不是正确结果
- if somevalue2 == DirectionEnum2.UP:
- # 不会运行, 没有使用 .value
- print('yes2')
- # 3. 第三种使用方式, OK, 并不是非常符合我们的习惯, 但是, 得到的预期结果是正确的
- if somevalue2 == DirectionEnum2.UP.value:
- # 运行, 使用了 .value
- print('yes2')
从上面我们可以看到, 如果仅仅是一些 int 类型的枚举集合, 那么使用 IntEnum 是 OK 的. 如果枚举集合的成分比较复杂, 那么就要使用 Enum, 虽然可以得到预期的正确结果, 但是却要改改自己的使用习惯, 强迫自己打出
DirectionEnum2.UP.value
这样的组合.
然而, 作为脑瓜子不好使的人来说,
DirectionEnum2.UP.value
这种我很难记住, 而且也不符合我的直觉啊, 另外, 我的大部分场景, 只是需要安安静静地使用一个枚举而已, 看 enum 库的内部实现, 又是元类, 又是委托啥的, 各种高科技都用上了. 所以, 我们就有强大的动力, 去适应自己, 而不是适应别人.
How to do
考虑到我们的使用场景非常单一 & 简单, 所以就想到了如下实现
- import functools
- class BaseEnum:
- @classmethod
- @functools.lru_cache(maxsize=1024)
- def values(cls):
- d = cls.__dict__
- return [v
- for k, v in d.items()
- if (not k.startswith('_')) and k.isupper()]
然后使用之, 这里我们通过写 UT 的形式去学习使用接口:
- from unittest import TestCase
- import py3utils
- class DirectionEnum(py3utils.BaseEnum):
- UP = 1
- DOWN = 2
- LEFT = 3
- RIGHT = 4
- class TestBaseEnum(TestCase):
- def test_values_is_list(self):
- self.assertTrue(isinstance(DirectionEnum.values(), list))
- def test_values(self):
- e = [1, 2, 3, 4]
- actual = DirectionEnum.values()
- self.assertEqual(e, actual)
- def test_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