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

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


当前回答

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

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',
))

其他回答

我需要在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类别。

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

dog, cat, rabbit = range(3)

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

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

我喜欢Java枚举,这就是我在Python中的做法:

def enum(clsdef):
    class Enum(object):
        __slots__=tuple([var for var in clsdef.__dict__ if isinstance((getattr(clsdef, var)), tuple) and not var.startswith('__')])

        def __new__(cls, *args, **kwargs):
            if not '_the_instance' in cls.__dict__:
                cls._the_instance = object.__new__(cls, *args, **kwargs)
            return cls._the_instance

        def __init__(self):
            clsdef.values=lambda cls, e=Enum: e.values()
            clsdef.valueOf=lambda cls, n, e=self: e.valueOf(n)
            for ordinal, key in enumerate(self.__class__.__slots__):
                args=getattr(clsdef, key)
                instance=clsdef(*args)
                instance._name=key
                instance._ordinal=ordinal
                setattr(self, key, instance)

        @classmethod
        def values(cls):
            if not hasattr(cls, '_values'):
                cls._values=[getattr(cls, name) for name in cls.__slots__]
            return cls._values

        def valueOf(self, name):
            return getattr(self, name)

        def __repr__(self):
            return ''.join(['<class Enum (', clsdef.__name__, ') at ', str(hex(id(self))), '>'])

    return Enum()

示例使用:

i=2
@enum
class Test(object):
    A=("a",1)
    B=("b",)
    C=("c",2)
    D=tuple()
    E=("e",3)

    while True:
        try:
            F, G, H, I, J, K, L, M, N, O=[tuple() for _ in range(i)]
            break;
        except ValueError:
            i+=1

    def __init__(self, name="default", aparam=0):
        self.name=name
        self.avalue=aparam

所有类变量都定义为元组,就像构造函数一样。到目前为止,还不能使用命名参数。

对于旧的Python 2.x

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

呵!

我喜欢使用列表或集合作为枚举。例如:

>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>