Python 枚举替代实现的缺陷

理解Python 枚举替代实现的缺陷,关于枚举最经典的例子大概非季节和星期莫属了,它能够以更接近自然语言的方式来表达数据,使得程序的可读性和可维护性大大提高。然而,很不幸,也许你习惯了其他语言中的枚举类型,但在Python3.4以前却并不提供。关于要不要加入枚举类型的问题就引起了不少讨论,在PEP354中曾提出增加枚举的建议,但被拒绝。于是人们充分利用Python的动态性这个特征,想出了枚举的各种替代实现方式。
1)使用类属性。

>>> class Seasons:
...     Spring = 0
...     Summer = 1
...     Autumn = 2
...     Winter = 3
...
>>> print Seasons.Spring

上面的例子可以直接简化为:

>>> class Seasons:
...     Spring,Summer,Autumn,Winter=range(4)
...

2)借助函数。

>>> def enum(*posarg, **keysarg):
...     return type("Enum", (object,), dict(zip(posarg, xrange(len(posarg))), **
keysarg))
...
>>> Seasons = enum("Spring","Summer","Autumn",Winter=1)
>>> Seasons.Spring
0
>>> Seasons = namedtuple('Seasons','Spring Summer Autumn Winter')._make(range(4))
>>> print Seasons.Spring
0

Python中枚举的替代实现方式远不止上述这些,在此就不一一列举了。那么,既然枚举在Python中有替代的实现方式,为什么人们还要执着地提出各自建议要求语言实现枚举呢?显然,这些替代实现有其不合理的地方。

  • 允许枚举值重复。我们以collections.namedtuple为例,下面的例子中枚举值Spring与Autumn相等,但却不会提示任何错误。
>>> Seasons._replace(Spring =2)
Seasons(Spring=2, Summter=1, Autumn=2, Winter=3) #Spring和Autumn的值相等,都为2
  • 支持无意义的操作。
>>> Seasons.Summer+Seasons.Autumn == Seasons.Winter
True #Seasons.Summer+Seasons.Autumn 相加无任何实际意义

实际上Python2.7以后的版本还有另外一种替代选择——使用第三方模块flufl.enum,它包含两种枚举类:一种是Enum,只要保证枚举值唯一即可,对值的类型没限制;还有一种是IntEnum,其枚举值为int型。

>>> from flufl.enum import Enum
>>> class Seasons(Enum):                       #
#继承自Enum定义枚举
...     Spring ="Spring"
...     Summer = 2
...     Autumn = 3
...     Winter = 4
...
>>> Seasons = Enum('Seasons', 'Spring Sumter Autumn Winter')

flufl.enum提供了__members__属性,可以对枚举名称进行迭代。

>>> for member in Seasons.__members__:
...     print member
...
Spring
Summer
Autumn
Winter

可以直接使用value属性获取枚举元素的值,如:

>>> print Seasons.Summer.value
2

flufl.enum不支持枚举元素的比较。

>>> Seasons.Summer <Seasons.Autumn     #flufl.enum不支持无意义的操作
Traceback (most recent call last):
... ...
    raise NotImplementedError
NotImplementedError

更多关于flufl.enum的使用可以参考网页http://Pythonhosted.org/flufl.enum/docs/using.html的内容。

值得一提的是,Python3.4中根据PEP435的建议终于加入了枚举Enum,其实现主要参考实现flufl.enum,但两者之间还是存在一些差别,如flufl.enum允许枚举继承,而Enum仅在父类没有任何枚举成员的时候才允许继承等,读者可以仔细阅读PEP435了解更多详情。另外,如果要在Python3.4之前的版本中使用枚举Enum,可以安装Enum的向后兼容包enum34,下载地址为https://pypi.Python.org/pypi/enum34

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!