当前位置:  开发笔记 > 编程语言 > 正文

我怎样才能用Python代表'Enum'?

如何解决《我怎样才能用Python代表'Enum'?》经验,为你挑选了25个好方法。

我主要是一名C#开发人员,但我目前正在使用Python开发一个项目.

我怎样才能在Python中表示Enum的等价物?



1> Alec Thomas..:

如PEP 435中所述,已将枚举添加到Python 3.4中.在pypi上它也被反向移植到 3.3,3.2,3.1,2.7,2.6,2.5 和2.4.

对于更高级的Enum技术,请尝试使用aenum库(2.7,3.3 +,同一作者enum34.代码在py2和py3之间不完全兼容,例如,你需要__order__在python 2中).

要使用enum34,做$ pip install enum34

要使用aenum,做$ pip install aenum

安装enum(无数字)将安装完全不同且不兼容的版本.


from enum import Enum     # for enum34, or the stdlib version
# from aenum import Enum  # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')

Animal.ant  # returns 
Animal['ant']  # returns  (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

或等效地:

class Animal(Enum):
    ant = 1
    bee = 2
    cat = 3
    dog = 4

在早期版本中,完成枚举的一种方法是:

def enum(**enums):
    return type('Enum', (), enums)

使用方式如下:

>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

您还可以使用以下内容轻松支持自动枚举:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

并使用如下:

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

可以通过以下方式添加对将值转换回名称的支持:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

这将覆盖具有该名称的任何内容,但它对于在输出中呈现您的枚举非常有用.如果反向映射不存在,它将抛出KeyError.第一个例子:

>>> Numbers.reverse_mapping['three']
'THREE'


哦,我注意到可以做出轻微的改进.`zip(x,range(len(x))`是一个代码气味 - 它可以被枚举替换为`enums = dict((x,i)代表i,x代表枚举(顺序)),**命名)``不构造zip/range所有的那些列表.
巧妙的解决方案!我想知道在调试时是否可以/如何打印标识符的名称?例如,有'print'值是%r"%Numbers.ONE`输出`值是ONE`而不是`值是1` ...
`enum`包的问题在于它的枚举类型在pickle-unpickling中无法生存.创建一个enumaration`Foo = Enum("foo","bar")`,然后比较`pickle.loads(pickle.dumps(Foo.foo))== Foo.foo`; 结果是'错误'.当你有一个多处理程序时会很痛,因为看似相等的值会停止通过相等检查.
请注意,这与C enum不太相似,因为它不能有意义地具有由`enum`返回的类型的变量/对象.
虽然值本身没有输入,但您可以键入枚举类,使它们彼此不同:`返回类型(named.get('enum_type','Enum'),(),枚举)`然后调用`enum('ONE','TWO',THREE ='three',enum_type ='Numbers')`
@sastanin:这不是stdlib的enum或enum34反向端口的问题。`Foo = Enum(“ Foo”,“ foo bar”)`,然后`pickle.loads(pickle.dumps(Foo.foo))== Foo.foo`是`True`。并且,如果您设法以某种方式混淆它(例如,Bar = Enum(“ Foo”,“ foo bar”)`),则会得到“ PicklingError”而不是无声失败。
将您的解决方案与PEP 435进行比较可能很有价值.

2> Alexandru Ne..:

在PEP 435之前,Python没有等效的,但你可以实现自己的.

我自己,我喜欢保持简单(我在网上看过一些非常复杂的例子),像这样......

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

在Python 3.4(PEP 435)中,您可以将Enum作为基类.这为您提供了一些额外的功能,如PEP中所述.例如,枚举成员与整数不同,它们由a name和a 组成value.

class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# 

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
# "DOG"

如果您不想键入值,请使用以下快捷方式:

class Animal(Enum):
    DOG, CAT = range(2)

Enum实现可以转换为列表并且是可迭代的.其成员的顺序是声明顺序,与其值无关.例如:

class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [, , ]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True


Python默认是动态的.没有正当理由在像Python这样的语言中强制执行编译时安全性,尤其是在没有Python的情况下.另一件事......一个好的模式只有在它创建的环境中才是好的.根据您使用的工具,良好的模式也可能被取代或完全无用.
我使用它,数字被`object()`替换.
不,这是一个类变量.
@Longpoke如果你有100个值,那么你肯定做错了;)我喜欢与我的枚举相关联的数字......它们易于编写(vs字符串),可以很容易地保存在数据库中,并且兼容C/C++枚举,使编组更容易.
最初的PEP354不再仅仅被拒绝,而是现在被标记为已被取代.PEP435为Python 3.4添加了标准的Enum.见http://www.python.org/dev/peps/pep-0435/
`X = object()`是不方便的,因为它不知道它是什么(你只能比较namespace.X),并且有风险因为copy.deepcopy()或serialization/deserialiaztion创建一个新的,而不是等于你定义的任何一个!数字至少是安全的,但字符串通常更好.
定义数值(1和2)有什么意义?它们似乎毫无用处,这就是为什么我更喜欢zacherates的解决方案.
使用范围通常更好
用字典更好地实现这一点,以便将动物类型与其序数值相匹配更容易吗?
@AlexandruNedelcu,每个到这个页面寻找这个问题答案的人都有充分的理由用枚举来强制执行有效的值.如何在修订版之间修改常量值时,如何强制执行A​​PI,提高可读性,改进IDE界面或限制效果?
从示例中可以清楚地看出,常量被定义.但是,类型安全存在问题,这可能会导致问题.

3> shahjapan..:

这是一个实现:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

这是它的用法:

Animals = Enum(["DOG", "CAT", "HORSE"])

print(Animals.DOG)


优秀.这可以通过重写`__setattr __(self,name,value)`和`__delattr __(self,name)`进一步改进,这样如果你不小心写了`Animals.DOG = CAT`,它就不会默默地成功.
@shahjapan:有趣但相对缓慢:对每个访问进行测试,如`Animals.DOG`; 另外,constats的值是字符串,因此与这些常量的比较比例如允许整数作为值更慢.
@AndréTerra:你如何检查``try-except``块中的集合成员资格?
@shahjapan:我认为这个解决方案并不像Alexandru或Mark的简短解决方案那样清晰.不过,这是一个有趣的解决方案.:)

4> Mark Harriso..:

如果您需要数值,这是最快的方法:

dog, cat, rabbit = range(3)

在Python 3.x中,您还可以在末尾添加一个带星号的占位符,这将占用该范围的所有剩余值,以防您不介意浪费内存并且无法计算:

dog, cat, rabbit, horse, *_ = range(100)



5> Ashwin Nanja..:

最适合您的解决方案取决于您对假货的 要求enum.

简单的枚举:

如果您enum只需要一个识别不同项目名称列表,Mark Harrison(上图)的解决方案很棒:

Pen, Pencil, Eraser = range(0, 3)

使用a range还允许您设置任何起始值:

Pen, Pencil, Eraser = range(9, 12)

除上述内容外,如果您还要求项目属于某种容器,则将它们嵌入到类中:

class Stationery:
    Pen, Pencil, Eraser = range(0, 3)

要使用枚举项,您现在需要使用容器名称和项目名称:

stype = Stationery.Pen

复杂的枚举:

对于冗长的枚举列表或更复杂的枚举用法,这些解决方案是不够的.您可以通过Python Cookbook中发布的Will Ware for Simulate Enumerations查看配方.这方面的一个在线版本,请点击这里.

更多信息:

PEP 354:Python中的枚举具有 Python中枚举的提议的有趣细节以及它被拒绝的原因.


使用`range`,如果它为0,你可以省略第一个参数

6> Aaron Maenpa..:

在Java JDK 5之前使用的类型安全枚举模式具有许多优点.就像Alexandru的回答一样,你创建一个类和类级别字段是枚举值; 但是,枚举值是类的实例而不是小整数.这样做的好处是你的枚举值不会无意中比较等于小整数,你可以控制它们的打印方式,添加任意方法(如果有用)并使用isinstance进行断言:

class Animal:
   def __init__(self, name):
       self.name = name

   def __str__(self):
       return self.name

   def __repr__(self):
       return "" % self

Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")

>>> x = Animal.DOG
>>> x

>>> x == 1
False

python-dev最近的一个帖子指出,野外有几个枚举库,包括:

flufl.enum

lazr.enum

...和想象力命名枚举


我认为这是一个非常糟糕的方法.Animal.DOG = Animal("dog")Animal.DOG2 = Animal("dog")断言Animal.DOG == Animal.DOG2失败......
"你的枚举值不会无意中比较等于小整数的优势"这有什么好处?将枚举与整数进行比较有什么问题?特别是如果将枚举存储在数据库中,通常希望将其存储为整数,因此您必须在某些时候将其与整数进行比较.
@Confusion用户不应该调用构造函数,甚至构造函数都是一个实现细节的事实,你必须与谁使用你的代码沟通,使新的枚举值没有意义,并且退出代码不会"做正确的事".当然,这并不能阻止你实现Animal.from_name("dog") - > Animal.DOG.
@AaronMcSmooth这真的取决于你是从C语言进入"Enums只是几个整数的名字"还是更加面向对象的方法,其中枚举值是实际对象并且有方法(这是Java中的枚举方式) 1.5是,并且类型安全枚举模式的目的是).就个人而言,我不喜欢switch语句,所以我倾向于实际对象的枚举值.
@Aaaron Maenpaa.正确.它仍然是一种破碎而过于复杂的方式.
现在尝试做Flags.FLAG1 | Flags.FLAG2,哦,它不起作用!

7> Zoetic..:

Enum类可以是单行.

class Enum(tuple): __getattr__ = tuple.index

如何使用它(正向和反向查找,键,值,项目等)

>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]



8> royal..:

所以,我同意.我们不要在Python中强制使用类型安全,但我想保护自己免受愚蠢的错误.那么我们怎么看?

class Animal(object):
    values = ['Horse','Dog','Cat']

    class __metaclass__(type):
        def __getattr__(self, name):
            return self.values.index(name)

在定义我的枚举时,它让我免于价值冲突.

>>> Animal.Cat
2

还有另一个便利的优势:真正快速的反向查找:

def name_of(self, i):
    return self.values[i]



9> dF...:

Python没有内置的等价物enum,其他答案也有实现自己的想法(你可能也对Python食谱中的顶级版本感兴趣).

但是,在enumC中需要调用的情况下,我通常最终只使用简单的字符串:由于实现了对象/属性的方式,(C)Python被优化为无论如何都能用短字符串快速工作,所以不会使用整数真的有任何性能优势.为了防止打字错误/无效值,您可以在选定位置插入支票.

ANIMALS = ['cat', 'dog', 'python']

def take_for_a_walk(animal):
    assert animal in ANIMALS
    ...

(与使用类相比,一个缺点是你失去了自动完成的好处)


我更喜欢这个解决方案 我喜欢尽可能使用内置类型.

10> Danilo Barge..:

在2013-05-10,Guido同意接受PEP 435进入Python 3.4标准库.这意味着Python最终内置了对枚举的支持!

Python 3.3,3.2,3.1,2.7,2.6,2.5和2.4提供了一个后端口.它在Pypi上作为enum34.

宣言:

>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3

表示:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))

迭代:

>>> for color in Color:
...   print(color)
...
Color.red
Color.green
Color.blue

程序化访问:

>>> Color(1)
Color.red
>>> Color['blue']
Color.blue

有关更多信息,请参阅提案.官方文档很快就会发布.



11> mbac32768..:

我喜欢在Python中定义枚举,如下所示:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

它比使用整数更容易出错,因为你不必担心确保整数是唯一的(例如,如果你说Dog = 1而Cat = 1你就会被搞砸).

它比使用字符串更容易出错,因为你不必担心拼写错误(例如x =="catt"无声地失败,但x == Animal.Catt是运行时异常).



12> 小智..:
def M_add_class_attribs(attribs):
    def foo(name, bases, dict_):
        for v, k in attribs:
            dict_[k] = v
        return type(name, bases, dict_)
    return foo

def enum(*names):
    class Foo(object):
        __metaclass__ = M_add_class_attribs(enumerate(names))
        def __setattr__(self, name, value):  # this makes it read-only
            raise NotImplementedError
    return Foo()

像这样使用它:

Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError

如果您只想要唯一符号而不关心值,请替换此行:

__metaclass__ = M_add_class_attribs(enumerate(names))

有了这个:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)


恕我直言,如果你把`enum(names)`改为`enum(*names)`那么它会更清晰 - 然后你可以在调用它时删除额外的括号.

13> dguaraglia..:

嗯...我想最接近枚举的是字典,定义如下:

months = {
    'January': 1,
    'February': 2,
    ...
}

要么

months = dict(
    January=1,
    February=2,
    ...
)

然后,您可以使用这样的常量的符号名称:

mymonth = months['January']

还有其他选项,如元组列表或元组元组,但字典是唯一一个为您提供"符号"(常量字符串)方式来访问该值的方法.

编辑:我也喜欢亚历山德鲁的答案!



14> agf..:

另一个非常简单的Python实现枚举,使用namedtuple:

from collections import namedtuple

def enum(*keys):
    return namedtuple('Enum', keys)(*keys)

MyEnum = enum('FOO', 'BAR', 'BAZ')

或者,或者,

# With sequential number values
def enum(*keys):
    return namedtuple('Enum', keys)(*range(len(keys)))

# From a dict / keyword args
def enum(**kwargs):
    return namedtuple('Enum', kwargs.keys())(*kwargs.values())

像上面的子类一样set,这允许:

'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO

但它具有更大的灵活性,因为它可以有不同的键和值.这允许

MyEnum.FOO < MyEnum.BAR

如果您使用填充序列号值的版本,则按预期行事.



15> Saša Šijak..:

从Python 3.4开始,官方将支持枚举.您可以在Python 3.4文档页面上找到文档和示例.

枚举是使用类语法创建的,这使它们易于读写.Functional API中描述了另一种创建方法.要定义枚举,请将Enum子类分配如下:

from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3



16> 小智..:

我用的是什么:

class Enum(object):
    def __init__(self, names, separator=None):
        self.names = names.split(separator)
        for value, name in enumerate(self.names):
            setattr(self, name.upper(), value)
    def tuples(self):
        return tuple(enumerate(self.names))

如何使用:

>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
   File "", line 1, in 
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))

因此,这为您提供了像state.PUBLISHED这样的整数常量以及在Django模型中用作选项的两元组.



17> 小智..:

davidg建议使用dicts.我更进一步,使用集合:

months = set('January', 'February', ..., 'December')

现在,您可以测试值是否与集合中的某个值匹配,如下所示:

if m in months:

但就像dF一样,我通常只使用字符串常量来代替枚举.



18> steveha..:

这是我见过的最好的:"Python中的一流枚举"

http://code.activestate.com/recipes/413486/

它为您提供了一个类,该类包含所有枚举.枚举可以相互比较,但没有任何特定的价值; 你不能将它们用作整数值.(我起初抵制这一点,因为我习惯于使用C枚举,这是整数值,但如果你不能把它作为一个整数,你不能把它当作错误的整数所以总体来说,我认为这是一个双赢.)每个枚举都是一个独特的值.你可以打印枚举,你可以迭代它们,你可以测试枚举值是否在枚举中".它非常完整和光滑.

编辑(cfi):上面的链接不兼容Python 3.这是我的Python 3的enum.py端口:

def cmp(a,b):
   if a < b: return -1
   if b < a: return 1
   return 0


def Enum(*names):
   ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!

   class EnumClass(object):
      __slots__ = names
      def __iter__(self):        return iter(constants)
      def __len__(self):         return len(constants)
      def __getitem__(self, i):  return constants[i]
      def __repr__(self):        return 'Enum' + str(names)
      def __str__(self):         return 'enum ' + str(constants)

   class EnumValue(object):
      __slots__ = ('__value')
      def __init__(self, value): self.__value = value
      Value = property(lambda self: self.__value)
      EnumType = property(lambda self: EnumType)
      def __hash__(self):        return hash(self.__value)
      def __cmp__(self, other):
         # C fans might want to remove the following assertion
         # to make all enums comparable by ordinal value {;))
         assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
         return cmp(self.__value, other.__value)
      def __lt__(self, other):   return self.__cmp__(other) < 0
      def __eq__(self, other):   return self.__cmp__(other) == 0
      def __invert__(self):      return constants[maximum - self.__value]
      def __nonzero__(self):     return bool(self.__value)
      def __repr__(self):        return str(names[self.__value])

   maximum = len(names) - 1
   constants = [None] * len(names)
   for i, each in enumerate(names):
      val = EnumValue(i)
      setattr(EnumClass, each, val)
      constants[i] = val
   constants = tuple(constants)
   EnumType = EnumClass()
   return EnumType


if __name__ == '__main__':
   print( '\n*** Enum Demo ***')
   print( '--- Days of week ---')
   Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
   print( Days)
   print( Days.Mo)
   print( Days.Fr)
   print( Days.Mo < Days.Fr)
   print( list(Days))
   for each in Days:
      print( 'Day:', each)
   print( '--- Yes/No ---')
   Confirmation = Enum('No', 'Yes')
   answer = Confirmation.No
   print( 'Your answer is not', ~answer)



19> danger89..:

把事情简单化:

class Enum(object): 
    def __init__(self, tupleList):
            self.tupleList = tupleList

    def __getattr__(self, name):
            return self.tupleList.index(name)

然后:

DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1



20> SingleNegati..:

为了解码二进制文件格式,我有机会需要一个Enum类.我碰巧想要的功能是简洁的枚举定义,通过整数值或字符串自由创建枚举实例的能力,以及有用的repr表达.这是我最终得到的:

>>> class Enum(int):
...     def __new__(cls, value):
...         if isinstance(value, str):
...             return getattr(cls, value)
...         elif isinstance(value, int):
...             return cls.__index[value]
...     def __str__(self): return self.__name
...     def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
...     class __metaclass__(type):
...         def __new__(mcls, name, bases, attrs):
...             attrs['__slots__'] = ['_Enum__name']
...             cls = type.__new__(mcls, name, bases, attrs)
...             cls._Enum__index = _index = {}
...             for base in reversed(bases):
...                 if hasattr(base, '_Enum__index'):
...                     _index.update(base._Enum__index)
...             # create all of the instances of the new class
...             for attr in attrs.keys():
...                 value = attrs[attr]
...                 if isinstance(value, int):
...                     evalue = int.__new__(cls, value)
...                     evalue._Enum__name = attr
...                     _index[value] = evalue
...                     setattr(cls, attr, evalue)
...             return cls
... 

使用它的一个异想天开的例子:

>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
... 
>>> Citrus.Lemon
Citrus.Lemon
>>> 
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
...     Apple = 3
...     Banana = 4
... 
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True

主要特点:

str(),int()并且repr()都产生尽可能最有用的输出,分别是enumartion的名称,它的整数值,以及计算回枚举的Python表达式.

构造函数返回的枚举值严格限制为预定义值,不包含偶然的枚举值.

枚举值是单例; 他们可以严格比较is



21> Riaz Rizvi..:

Python中的新标准是PEP 435,因此未来的Python版本中将提供Enum类:

>>> from enum import Enum

但是,现在开始使用它可以安装激发PEP 的原始库:

$ pip install flufl.enum

然后您可以按照其在线指南使用它:

>>> from flufl.enum import Enum
>>> class Colors(Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue



22> estani..:
def enum(*sequential, **named):
    enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
    return type('Enum', (), enums)

如果你命名它,是你的问题,但如果没有创建对象而不是值允许你这样做:

>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False

当使用此处的其他实现时(在我的示例中使用命名实例时),您必须确保永远不会尝试比较来自不同枚举的对象.对于这里可能存在的陷阱:

>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True

哎呀!



23> bj0..:

我非常喜欢Alec Thomas的解决方案(http://stackoverflow.com/a/1695250):

def enum(**enums):
    '''simple constant "enums"'''
    return type('Enum', (object,), enums)

它看起来优雅而干净,但它只是一个创建具有指定属性的类的函数.

通过对该功能的一点修改,我们可以让它更加"笨拙":

注意:我通过尝试重现pygtk的新样式"枚举"(如Gtk.MessageType.WARNING)的行为来创建以下示例

def enum_base(t, **enums):
    '''enums with a base class'''
    T = type('Enum', (t,), {})
    for key,val in enums.items():
        setattr(T, key, T(val))

    return T

这将创建一个基于指定类型的枚举.除了像上一个函数一样提供属性访问之外,它的行为与您期望Enum相对于类型的行为一样.它还继承了基类.

例如,整数枚举:

>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)

>>> type(Numbers.ONE)

>>> isinstance(x, Numbers)
True

使用此方法可以完成的另一个有趣的事情是通过覆盖内置方法来自定义特定行为:

def enum_repr(t, **enums):
    '''enums with a base class and repr() output'''
    class Enum(t):
        def __repr__(self):
            return ''.format(self._name, t.__name__)

    for key,val in enums.items():
        i = Enum(val)
        i._name = key
        setattr(Enum, key, i)

    return Enum



>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
''
>>> str(Numbers.ONE)
'1'



24> pythonic met..:

PyPI的枚举包提供了强大的枚举实现.早先的回答提到了PEP 354; 这被拒绝但提案已经实施 http://pypi.python.org/pypi/enum.

用法简单而优雅:

>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'



25> 小智..:

Alexandru建议在枚举中使用类常量非常有效.

我还想为每组常量添加一个字典来查找人类可读的字符串表示.

这有两个目的:a)它提供了一种简单的方法来打印你的枚举和b)字典在逻辑上对常量进行分组,以便你可以测试成员资格.

class Animal:    
  TYPE_DOG = 1
  TYPE_CAT = 2

  type2str = {
    TYPE_DOG: "dog",
    TYPE_CAT: "cat"
  }

  def __init__(self, type_):
    assert type_ in self.type2str.keys()
    self._type = type_

  def __repr__(self):
    return "<%s type=%s>" % (
        self.__class__.__name__, self.type2str[self._type].upper())

推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有