我应该如何最好地模仿和/或避免使用Python中的枚举?

How should I best emulate and/or avoid enum's in Python?

本问题已经有最佳答案,请猛点这里访问。

我在一些Python项目中使用了一个小类来模拟枚举。有没有更好的方法,或者在某些情况下这是最有意义的?

此处为类代码:

1
2
3
4
5
6
7
class Enum(object):
'''Simple Enum Class
Example Usage:
>>> codes = Enum('FOO BAR BAZ') # codes.BAZ will be 2 and so on ...'''

def __init__(self, names):
    for number, name in enumerate(names.split()):
        setattr(self, name, number)


Enums以前曾被提议包含在该语言中,但被拒绝(见http://www.python.org/dev/peps/pep-0354/),尽管您可以使用现有的包来代替编写自己的实现:

  • 枚举:http://pypi.python.org/pypi/enum
  • symboltype(与enums不完全相同,但仍然有用):http://pypi.python.org/pypi/symboltype
  • 或者只是搜索一下

最常见的枚举情况是作为状态或策略设计模式一部分的枚举值。枚举是要使用的特定状态或特定可选策略。在这种情况下,它们几乎总是某些类定义的一部分。

1
2
3
4
5
6
7
class DoTheNeedful( object ):
    ONE_CHOICE = 1
    ANOTHER_CHOICE = 2
    YET_ANOTHER = 99
    def __init__( self, aSelection ):
        assert aSelection in ( self.ONE_CHOICE, self.ANOTHER_CHOICE, self.YET_ANOTHER )
        self.selection= aSelection

然后,在这个类的客户机中。

1
dtn = DoTheNeeful( DoTheNeeful.ONE_CHOICE )


这里有很多很好的讨论。


我更经常看到的是,在顶层模块上下文中:

1
2
3
FOO_BAR = 'FOO_BAR'
FOO_BAZ = 'FOO_BAZ'
FOO_QUX = 'FOO_QUX'

……后来…

1
2
3
4
if something is FOO_BAR: pass # do something here
elif something is FOO_BAZ: pass # do something else
elif something is FOO_QUX: pass # do something else
else: raise Exception('Invalid value for something')

注意,使用is而不是==在这里是有风险的——它假设人们使用的是your_module.FOO_BAR,而不是字符串'FOO_BAR'(通常是这样的,is将匹配,但这当然不能计算在内),因此根据上下文,可能不合适。

这样做的一个好处是,通过查看存储该字符串的引用的任何位置,可以立即发现它来自何处;FOO_BAZ2更不含糊。

除此之外,还有一件事冒犯了我对脓毒气的敏感性,那就是你所建议的使用split()。为什么不先传入一个元组、列表或其他可枚举项?


执行枚举的内置方法是:

1
(FOO, BAR, BAZ) = range(3)

它对小装置很有用,但也有一些缺点:

  • 你需要手工计算元素的数量
  • 不能跳过值
  • 如果添加一个名称,还需要更新范围号

有关python中的完整枚举实现,请参见:http://code.activestate.com/recipes/67107/


我从看起来很像s.lott的答案开始,但我只重载了"str"和"eq"(而不是整个对象类),这样我就可以打印和比较枚举的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class enumSeason():
    Spring = 0
    Summer = 1
    Fall = 2
    Winter = 3
    def __init__(self, Type):
        self.value = Type
    def __str__(self):
        if self.value == enumSeason.Spring:
            return 'Spring'
        if self.value == enumSeason.Summer:
            return 'Summer'
        if self.value == enumSeason.Fall:
            return 'Fall'
        if self.value == enumSeason.Winter:
            return 'Winter'
    def __eq__(self,y):
        return self.value==y.value

print(x)将生成名称而不是值,两个保持弹簧的值将相等。

1
2
3
4
5
6
   >>> x = enumSeason(enumSeason.Spring)
   >>> print(x)
   Spring
   >>> y = enumSeason(enumSeason.Spring)
   >>> x == y
   True