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') |
注意,使用
这样做的一个好处是,通过查看存储该字符串的引用的任何位置,可以立即发现它来自何处;
除此之外,还有一件事冒犯了我对脓毒气的敏感性,那就是你所建议的使用
执行枚举的内置方法是:
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 |