我应该如何最好地模拟和/或者避免在Python中使用枚举?
时间:2020-03-06 14:29:14 来源:igfitidea点击:
我一直在使用一个小类在某些Python项目中模拟Enums。有没有更好的方法,或者这在某些情况下最有意义?
此处的类代码:
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)
解决方案
枚举曾经被提议包含在语言中,但是被拒绝了(请参阅http://www.python.org/dev/peps/pep-0354/),尽管我们可以使用现有的软件包来代替编写自己的实现:
- 枚举:http://pypi.python.org/pypi/enum
- SymbolType(与枚举不完全相同,但仍然有用):http://pypi.python.org/pypi/SymbolType
- 或者只是进行搜索
枚举的内置方法是:
(FOO, BAR, BAZ) = range(3)
它适用于小型设备,但有一些缺点:
- 我们需要手工计算元素的数量
- 你不能跳过值
- 如果添加一个名称,则还需要更新范围号
有关python中完整的枚举实现,请参见:
http://code.activestate.com/recipes/67107/
在顶层模块上下文中,我经常看到的是:
FOO_BAR = 'FOO_BAR' FOO_BAZ = 'FOO_BAZ' FOO_QUX = 'FOO_QUX'
...然后...
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'
(通常会被<I> (是)将匹配,但肯定不能指望),因此根据上下文可能不适当。
这种方式的一个优点是,通过在任何地方存储对该字符串的引用,都可以立即发现它的来源; " FOO_BAZ"比" 2"的含义要少得多。
除此之外,令我们提议的类冒犯我的Python感的另一件事是使用split()
。为什么不只是传入一个元组,列表或者其他可枚举的内容呢?
这里有很多很好的讨论。
最常见的枚举情况是作为州或者策略设计模式一部分的枚举值。枚举是要使用的特定状态或者特定可选策略。在这种情况下,它们几乎总是某些类定义的组成部分
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
然后,在此类的客户中。
dtn = DoTheNeeful( DoTheNeeful.ONE_CHOICE )
我从一个看起来很像S.Lott答案的东西开始,但是我只重载了" str"和" eq"(而不是整个对象类),因此我可以打印和比较枚举的值。
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)将产生名称而不是值,并且保存Spring的两个值将彼此相等。
>>> x = enumSeason(enumSeason.Spring) >>> print(x) Spring >>> y = enumSeason(enumSeason.Spring) >>> x == y True