懒人在思考 2017-12-03
首先便是业务代码中会出现巨量的 XXType 之类的东西,业务越复杂,这种东西就越多,它们符合 enum 的基本假定,用 enum 去管理这些常量是很自然的想法。
其次便是 Python 并没有实现 enum 这一抽象手段(其实我极其希望加入这一特性,另一个希望加入的特性是 const )。
方式1:模块级别常量:
这也是标准库和许多流行库的做法,比如:
# direction.py UP = 1 DOWN = 2 LEFT = 3 RIGHT = 4
方式2:使用 enum 库
Python 2 和Python 3 均可使用,Python 3 更是直接变为标准库,从侧面可知道 enum 这种东西的重要性。
典型使用:
import enum import unittest class BaseEnum(enum.Enum): """一般都会再次封装下, 后文详述原因""" @classmethod def values(cls): """获取右边value的集合 因为我们经常要用到 xxvalue in xxEnum.values(), 这是我们 封装的原因与初衷 :return: """ values = [] for attr in cls: values.append(attr.value) return values class DirectionEnum(BaseEnum): """使用""" UP = 1 DOWN = 2 LEFT = 3 RIGHT = 4 ######################### 单元测试 ########################## class TestBaseEnum(unittest.TestCase): def test_values(self): expected = frozenset((DirectionEnum.UP.value, DirectionEnum.DOWN.value, DirectionEnum.LEFT.value, DirectionEnum.RIGHT.value)) actual = frozenset(DirectionEnum.values()) self.assertSetEqual(expected, actual) def test_value_in(self): value = 1 self.assertTrue(value in DirectionEnum.values()) def test_value_equal(self): value = 1 self.assertTrue(value == DirectionEnum.UP.value)
上面的几种做法已经覆盖得很全面了,我完全没必要自己再去弄一个丑陋的轮子。
之所以不用方式1,因为 module 对我而言是一个很重要的命名空间,直接把常量挂载在其下面,对我而言是一种浪费。
之所以不用方式2,完全是因为我有点不喜欢 xxvalue == DirectionEnum.UP.value
这种写法(难道不是 xxvalue == DirectionEnum.UP
这种写法更加自然吗?)。但是总的来说,enum 库毕竟是大神的作品,而且也实现了 enum 这一概念的的方方面面,我们自然可以放心使用,而且我也推荐使用。:)
我最终还是选择了一种适合自己业务场景的一种使用方式,虽然土,但总还算是 work。
import unittest import abc class BaseEnum(abc.ABC): @abc.abstractclassmethod def values(cls): cls_dict = cls.__dict__ return [cls_dict[key] for key in cls_dict.keys() if not key.startswith('_') and key.isupper()] class DirectionEnum(BaseEnum): UP = 1 DOWN = 2 LEFT = 3 RIGHT = 4 ######################## 单元测试 ################################ class TestBaseEnum(unittest.TestCase): def test_values(self): expected = frozenset([DirectionEnum.UP, DirectionEnum.DOWN, DirectionEnum.LEFT, DirectionEnum.RIGHT]) actual = frozenset(DirectionEnum.values()) self.assertSetEqual(expected, actual) def test_value_in(self): value = 1 self.assertTrue(value in DirectionEnum.values()) def test_value_equal(self): value = 1 self.assertTrue(value == DirectionEnum.UP)
其实更加希望在语言级别提供常量管理的常用手段,而不是为了 simple 而 simple(并没有什么意义)。