返回介绍

建议11:理解枚举替代实现的缺陷

发布于 2024-01-30 22:19:09 字数 2518 浏览 0 评论 0 收藏 0

关于枚举最经典的例子大概非季节和星期莫属了,它能够以更接近自然语言的方式来表达数据,使得程序的可读性和可维护性大大提高。然而,很不幸,也许你习惯了其他语言中的枚举类型,但在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

3)使用collections.namedtuple。

>>> 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。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文