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

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


当前回答

这是我在这里找到的一个很好的Python食谱:http://code.activestate.com/recipes/577024-yet-another-enum-for-python/

def enum(typename, field_names):
    "Create a new enumeration type"

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    d = dict((reversed(nv) for nv in enumerate(field_names)), __slots__ = ())
    return type(typename, (object,), d)()

使用示例:

STATE = enum('STATE', 'GET_QUIZ, GET_VERSE, TEACH')

更多细节可以在食谱页面上找到。

其他回答

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

dog, cat, rabbit = range(3)

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

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

在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

最好的解决方案取决于你需要从你的假枚举中得到什么。

简单的枚举:

如果你只需要枚举作为标识不同项目的名称列表,Mark Harrison(上图)的解决方案是很棒的:

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

使用范围还允许你设置任何起始值:

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

除此之外,如果你还要求项属于某种类型的容器,那么将它们嵌入到一个类中:

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

要使用枚举项,你现在需要使用容器名和项名:

stype = Stationery.Pen

复杂的枚举:

对于枚举的长列表或更复杂的enum使用,这些解决方案是不够的。你可以参考Will Ware在Python Cookbook中发布的关于在Python中模拟枚举的食谱。这里有一个在线版本。

更多信息:

PEP 354: Python中的枚举有关于Python中的枚举建议的有趣细节,以及为什么它被拒绝。

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

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

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

通过对函数进行一些修改,我们可以让它表现得更像“枚举”:

注意:我通过尝试重现 pygtk的新样式'enums'的行为(如gtk . messagtype . 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对类型的行为一样。它还继承了基类。

例如,整数enum:

>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True

用这个方法还可以做一件有趣的事情,那就是通过覆盖内置方法来定制特定的行为:

def enum_repr(t, **enums):
    '''enums with a base class and repr() output'''
    class Enum(t):
        def __repr__(self):
            return '<enum {0} of type Enum({1})>'.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)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'

我需要在pyparsing中使用一些符号常量来表示二进制运算符的左右结合性。我像这样使用类常量:

# an internal class, not intended to be seen by client code
class _Constants(object):
    pass


# an enumeration of constants for operator associativity
opAssoc = _Constants()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()

现在当客户端代码想要使用这些常量时,他们可以使用以下方法导入整个枚举:

import opAssoc from pyparsing

枚举是唯一的,它们可以用'is'而不是'=='来测试,它们不会在我的代码中占用很大的空间,而且它们很容易导入到客户端代码中。它们不支持任何花哨的str()行为,但到目前为止,这属于YAGNI类别。