我主要是c#开发人员,但我目前正在用Python开发一个项目。

我如何在Python中表示等价的Enum ?


当前回答

为什么枚举必须是整数?不幸的是,在不改变Python语言的情况下,我想不出任何好看的构造来生成它,所以我将使用字符串:

class Enumerator(object):
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        if self.name == other:
            return True
        return self is other

    def __ne__(self, other):
        if self.name != other:
            return False
        return self is other

    def __repr__(self):
        return 'Enumerator({0})'.format(self.name)

    def __str__(self):
        return self.name

class Enum(object):
    def __init__(self, *enumerators):
        for e in enumerators:
            setattr(self, e, Enumerator(e))
    def __getitem__(self, key):
        return getattr(self, key)

也许现在更好的是,为了配置文件或其他远程输入,我们可以自然地对字符串进行测试。

例子:

class Cow(object):
    State = Enum(
        'standing',
        'walking',
        'eating',
        'mooing',
        'sleeping',
        'dead',
        'dying'
    )
    state = State.standing

In [1]: from enum import Enum

In [2]: c = Cow()

In [3]: c2 = Cow()

In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))

In [5]: c.state == c2.state
Out[5]: True

In [6]: c.State.mooing
Out[6]: Enumerator(mooing)

In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)

In [8]: c.state = Cow.State.dead

In [9]: c.state == c2.state
Out[9]: False

In [10]: c.state == Cow.State.dead
Out[10]: True

In [11]: c.state == 'dead'
Out[11]: True

In [12]: c.state == Cow.State['dead']
Out[11]: True

其他回答

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

就我个人而言,我喜欢保持简单(我在网上看到过一些非常复杂的例子),就像这样……

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

在Python 3.4 (PEP 435)中,可以将Enum作为基类。这为您提供了一些额外的功能,详见PEP。例如,enum成员不同于整数,它们由名称和值组成。

from enum import Enum

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

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

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

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

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

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

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

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

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

Animal.CAT in Animal
# True

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

dog, cat, rabbit = range(3)

在Python 3中。X你也可以在最后添加一个星号占位符,它将吸收范围内所有剩余的值,以防你不介意浪费内存和无法计数:

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

这个解决方案是获取定义为列表的枚举类的简单方法(没有更多烦人的整数赋值):

enumeration.py:

import new

def create(class_name, names):
    return new.classobj(
        class_name, (object,), dict((y, x) for x, y in enumerate(names))
    )

example.py:

import enumeration

Colors = enumeration.create('Colors', (
    'red',
    'orange',
    'yellow',
    'green',
    'blue',
    'violet',
))

在Java pre-JDK 5中使用的类型安全枚举模式有一个 优势的数量。就像Alexandru的回答一样,你创建了一个 类和类级别字段是枚举值;然而,枚举 值是类的实例,而不是小整数。这已经 优点是枚举值不会在不经意间比较相等 对于小整数,你可以控制它们的打印方式,任意添加 方法(如果有用的话),并使用isinstance进行断言:

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

   def __str__(self):
       return self.name

   def __repr__(self):
       return "<Animal: %s>" % self

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

>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False

python-dev上最近的一个线程指出,在野外有几个枚举库,包括:

flufl.enum lazr.enum ... 和富有想象力的enum

在答案列表中没有看到这个,这是我想出的一个。它允许使用'in'关键字和len()方法:

class EnumTypeError(TypeError):
    pass

class Enum(object):
    """
    Minics enum type from different languages
    Usage:
    Letters = Enum(list('abc'))
    a = Letters.a
    print(a in Letters) # True
    print(54 in Letters) # False
    """
    def __init__(self, enums):
        if isinstance(enums, dict):
            self.__dict__.update(enums)
        elif isinstance(enums, list) or isinstance(enums, tuple):
            self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
        else:
            raise EnumTypeError

    def __contains__(self, key):
        return key in self.__dict__.values()

    def __len__(self):
        return len(self.__dict__.values())


if __name__ == '__main__':
    print('Using a dictionary to create Enum:')
    Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    print('\nUsing a list to create Enum:')
    Letters = Enum(list('abcde'))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    try:
        # make sure we raise an exception if we pass an invalid arg
        Failure = Enum('This is a Failure')
        print('Failure')
    except EnumTypeError:
        print('Success!')

输出:

Using a dictionary to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5

Using a list to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5
Success!