Python中的枚举类

Enum class in python

本问题已经有最佳答案,请猛点这里访问。

我想在python中创建一个枚举类。我还需要一些get_str()方法,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Operation (object):
    START = 0
    STOP = 1
    (...)

    def get_str(self):
        operation_dispatcher = {
             Operation.START:"start",
             Operation.STOP:"stop",
             (...)

             }
    return operation_dispatcher[self]

但不幸的是,这种方法不起作用。对象是ints,我收到错误消息"int"对象没有属性"get_str"…你知道如何实现这个功能吗?

我试着做如下的事情:

operation.get_str(operation_reference)和operation_reference.get_str()。

更新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class EnumMeta(type):
    def __getattribute__(self, name):
        return self(super(EnumMeta, self).__getattribute__(name))

class Enum(object):
    __metaclass__ = EnumMeta

    def __init__(self, value):
        super(Enum, self).__init__()

        self.value = value[0]
        self.repr = value[1]

    def __eq__(self, other):
        if isinstance(other, Enum):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return object.__eq__(Enum, other)

    def __repr__(self):
        return str(self.repr)

class Operation(Enum):
    START = (0,"start")
    STOP = (1,"stop")
    (...)

operation_dispatcher = {
             Operation.START: start_method,
             Operation.STOP: stop_method,
             (...) }

# invoking
operation_dispatcher[Operation.START.value]()


python中的Enum可以是:

  • 从python 3.4开始内置
  • 可作为从python3.3到python2.4的后端端口使用
  • 可在增强型库中使用,该库还包括基于类的NamedTupleConstant类。

使用它,您的代码看起来像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from aenum import IntEnum   # or from enum import IntEnum

class Operation(IntEnum):
    START = 0
    STOP = 1

>>> Operation.START
<Operation.START: 0>

>>> Operation['START']
<Operation.START: 0>

>>> Operation(0)
<Operation.START: 0>

>>> Operation.STOP is Operation.STOP
True

>>> list(Operation)
[<Operation.START: 0>, <Operation.STOP: 1>]

>>> Operation.STOP.name
'STOP'

>>> Operation.STOP.value
1

我建议您使用元类来实现目标,以最小化客户机代码。所以首先检查下面的元类:

1
2
3
4
5
6
7
8
9
class EnumMeta(type):
    def __getattribute__(self, name):
        actual_value = super(EnumMeta, self).__getattribute__(name)
        if isinstance(actual_value, self):
            return actual_value
        else:
            new_value = self(actual_value)
            super(EnumMeta, self).__setattr__(name, new_value)
            return new_value

它只重写__getattribute__,并返回使用属性值作为构造函数参数的子类实例。此外,它还会更新原始值,以避免每次都创建新实例,并使用对象的引用进行相等性检查。

然后这样定义一个Enum类:

1
2
3
4
5
6
7
8
9
10
11
class Enum(object):
    __metaclass__ = EnumMeta

    def __init__(self, value):
        super(Enum, self).__init__()

        self.value = value[0]
        self.repr = value[1]

    def __repr__(self):
        return str(self.repr)

该基类实现equals(==运算符,以便使用int值和__repr__方法进行比较,以返回枚举的字符串表示形式。所以,你走吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Operation(Enum):
    START = (0,"start")
    STOP = (1,"stop")

>>> Operation.START == Operation.START
True
>>> Operation.START is Operation.START
True
>>> Operation.START == Operation.STOP
False
>>> Operation.START
"start"
>>> repr(Operation.STOP)
"stop"