我如何在Python中表示“枚举”?

时间:2021-07-19 18:35:05

I'm mainly a C# developer, but I'm currently working on a project in Python.

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

How can I represent the equivalent of an Enum in Python?

如何表示Python中枚举的等效项?

43 个解决方案

#1


2262  

Enums have been added to Python 3.4 as described in PEP 435. It has also been backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 on pypi.

Enums被添加到Python 3.4中,正如PEP 435中所描述的那样。在pypi上,它还被反向移植到3.3、3.2、3.1、2.7、2.6、2.5和2.4。

For more advanced Enum techniques try the aenum library (2.7, 3.3+, same author as enum34. Code is not perfectly compatible between py2 and py3, e.g. you'll need __order__ in python 2).

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

  • To use enum34, do $ pip install enum34
  • 要使用enum34,请使用$ pip安装enum34。
  • To use aenum, do $ pip install aenum
  • 要使用枚举,请执行$ pip安装aenum。

Installing enum (no numbers) will install a completely different and incompatible version.

安装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: 1>
Animal['ant']  # returns <Animal.ant: 1> (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

or equivalently:

或者说:

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

In earlier versions, one way of accomplishing enums is:

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

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

which is used like so:

它是这样使用的:

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

You can also easily support automatic enumeration with something like this:

您还可以轻松地支持自动枚举,例如:

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

and used like so:

并使用如下所示:

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

Support for converting the values back to names can be added this way:

支持将值转换回名称可以这样添加:

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)

This overwrites anything with that name, but it is useful for rendering your enums in output. It will throw KeyError if the reverse mapping doesn't exist. With the first example:

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

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

#2


704  

Before PEP 435, Python didn't have an equivalent but you could implement your own.

在PEP 435之前,Python没有类似的功能,但是您可以实现自己的。

Myself, I like keeping it simple (I've seen some horribly complex examples on the net), something like this ...

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

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum values are distinct from integers.

在Python 3.4 (PEP 435)中,您可以将Enum作为基类。这为您提供了一些额外的功能,在PEP中描述。例如,枚举值与整数不同。

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

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

If you don't want to type the values, use the following shortcut:

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

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

#3


294  

Here is one implementation:

这里是一个实现:

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

Here is its usage:

这是它的用法:

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

print(Animals.DOG)

#4


176  

If you need the numeric values, here's the quickest way:

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

dog, cat, rabbit = range(3)

In Python 3.x you can also add a starred placeholder at the end, which will soak up all the remaining values of the range in case you don't mind wasting memory and cannot count:

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

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

#5


117  

The best solution for you would depend on what you require from your fake enum.

对于您来说,最好的解决方案将取决于您在模拟枚举中所需要的内容。

Simple enum:

简单的枚举:

If you need the enum as only a list of names identifying different items, the solution by Mark Harrison (above) is great:

如果您需要枚举列表,只是一个标识不同项目的名称列表,那么Mark Harrison(上面)的解决方案很好:

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

Using a range also allows you to set any starting value:

使用范围也允许您设置任何起始值:

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

In addition to the above, if you also require that the items belong to a container of some sort, then embed them in a class:

此外,如果您还要求项目属于某种容器,那么将它们嵌入到类中:

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

To use the enum item, you would now need to use the container name and the item name:

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

stype = Stationery.Pen

Complex enum:

复杂的枚举:

For long lists of enum or more complicated uses of enum, these solutions will not suffice. You could look to the recipe by Will Ware for Simulating Enumerations in Python published in the Python Cookbook. An online version of that is available here.

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

More info:

更多信息:

PEP 354: Enumerations in Python has the interesting details of a proposal for enum in Python and why it was rejected.

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

#6


75  

The typesafe enum pattern which was used in Java pre-JDK 5 has a number of advantages. Much like in Alexandru's answer, you create a class and class level fields are the enum values; however, the enum values are instances of the class rather than small integers. This has the advantage that your enum values don't inadvertently compare equal to small integers, you can control how they're printed, add arbitrary methods if that's useful and make assertions using isinstance:

在Java jdk 5中使用的typesafe enum模式有很多优点。与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

A recent thread on python-dev pointed out there are a couple of enum libraries in the wild, including:

python-dev最近的一个帖子指出,在野生环境中有几个enum库,包括:

#7


52  

An Enum class can be a one-liner.

Enum类可以是一行程序。

class Enum(tuple): __getattr__ = tuple.index

How to use it (forward and reverse lookup, keys, values, items, etc.)

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

>>> 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


43  

Python doesn't have a built-in equivalent to enum, and other answers have ideas for implementing your own (you may also be interested in the over the top version in the Python cookbook).

Python没有一个内置的等效于enum,其他的答案有实现自己的想法(您可能也对Python cookbook中的*版本感兴趣)。

However, in situations where an enum would be called for in C, I usually end up just using simple strings: because of the way objects/attributes are implemented, (C)Python is optimized to work very fast with short strings anyway, so there wouldn't really be any performance benefit to using integers. To guard against typos / invalid values you can insert checks in selected places.

但是,在需要用C调用enum的情况下,我通常只使用简单的字符串:由于对象/属性的实现方式,(C)Python被优化为以短字符串快速工作,因此使用整数不会有任何性能好处。为了防止输入错误/无效值,您可以在选定的位置插入检查。

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

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

(One disadvantage compared to using a class is that you lose the benefit of autocomplete)

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

#9


43  

So, I agree. Let's not enforce type safety in Python, but I would like to protect myself from silly mistakes. So what do we think about this?

所以,我同意。让我们不要在Python中强制执行类型安全,但是我希望保护自己避免犯愚蠢的错误。我们怎么想呢?

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

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

It keeps me from value-collision in defining my enums.

它使我在定义我的枚举时避免了价值冲突。

>>> Animal.Cat
2

There's another handy advantage: really fast reverse lookups:

还有一个便利的优点:快速反向查找:

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

#10


29  

On 2013-05-10, Guido agreed to accept PEP 435 into the Python 3.4 standard library. This means that Python finally has builtin support for enumerations!

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

There is a backport available for Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4. It's on Pypi as enum34.

对于Python 3.3、3.2、3.1、2.7、2.6、2.5和2.4,有一个backport可用。它在Pypi上,如enum34。

Declaration:

声明:

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

Representation:

表示:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

Iteration:

迭代:

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

Programmatic access:

编程访问:

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

For more information, refer to the proposal. Official documentation will probably follow soon.

要了解更多信息,请参考建议。官方文件可能很快就会出台。

#11


28  

I prefer to define enums in Python like so:

我更喜欢用Python来定义枚举:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

It's more bug-proof than using integers since you don't have to worry about ensuring that the integers are unique (e.g. if you said Dog = 1 and Cat = 1 you'd be screwed).

它比使用整数更容易出错,因为您不必担心确保整数是唯一的(例如,如果您说Dog = 1和Cat = 1,您就会被搞糊涂了)。

It's more bug-proof than using strings since you don't have to worry about typos (e.g. x == "catt" fails silently, but x == Animal.Catt is a runtime exception).

它比使用字符串更能防止bug,因为您不必担心拼写错误(例如,x == "catt"会在沉默中失败,但是x ==动物)。Catt是一个运行时异常。

#12


28  

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()

Use it like this:

使用它是这样的:

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

if you just want unique symbols and don't care about the values, replace this line:

如果你只是想要唯一的符号,而不关心这些值,就替换这条线:

__metaclass__ = M_add_class_attribs(enumerate(names))

with this:

用这个:

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

#13


20  

Another, very simple, implementation of an enum in Python, using namedtuple:

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

from collections import namedtuple

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

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

or, alternatively,

,或者

# 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())

Like the method above that subclasses set, this allows:

类似于子类设置的方法,它允许:

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

But has more flexibility as it can have different keys and values. This allows

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

MyEnum.FOO < MyEnum.BAR

to act as is expected if you use the version that fills in sequential number values.

如果您使用填充了顺序编号值的版本,则可以按照预期的方式行事。

#14


18  

Hmmm... I suppose the closest thing to an enum would be a dictionary, defined either like this:

嗯…我认为最接近enum的是一本字典,它的定义是这样的:

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

or

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

Then, you can use the symbolic name for the constants like this:

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

mymonth = months['January']

There are other options, like a list of tuples, or a tuple of tuples, but the dictionary is the only one that provides you with a "symbolic" (constant string) way to access the value.

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

Edit: I like Alexandru's answer too!

编辑:我也喜欢Alexandru的答案!

#15


16  

What I use:

我使用:

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

How to use:

如何使用:

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

So this gives you integer constants like state.PUBLISHED and the two-tuples to use as choices in Django models.

这就得到了像状态一样的整型常数。已发布和两元组作为Django模型的选择。

#16


14  

davidg recommends using dicts. I'd go one step further and use sets:

davidg建议使用字典。我将更进一步,使用集合:

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

Now you can test whether a value matches one of the values in the set like this:

现在您可以测试一个值是否与set中的值相匹配:

if m in months:

like dF, though, I usually just use string constants in place of enums.

像dF一样,我通常只使用字符串常量代替enums。

#17


13  

This is the best one I have seen: "First Class Enums in Python"

这是我见过的最好的一个:“Python中的第一个类枚举”

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

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

It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don't have any particular value; you can't use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can't use it as an integer, you can't use it as an integer by mistake so overall I think it is a win.) Each enum is a unique value. You can print enums, you can iterate over them, you can test that an enum value is "in" the enum. It's pretty complete and slick.

它给你一个类,这个类包含所有的枚举。枚举可以相互比较,但是没有任何特定的值;不能将其作为整数值使用。(一开始我反对这个,因为我习惯了C枚举,它是整数值。但是如果你不能把它作为一个整数来使用,你不能把它当作一个整数来使用,所以总的来说,我认为它是一个胜利。每个enum都是一个独特的值。您可以打印枚举,您可以迭代它们,您可以测试枚举值“在”枚举中。它非常完整和光滑。

Edit (cfi): The above link is not Python 3 compatible. Here's my port of enum.py to Python 3:

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

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)

#18


13  

From Python 3.4 there will be official support for enums. You can find documentation and examples here on Python 3.4 documentation page.

从Python 3.4中可以得到对enums的官方支持。您可以在Python 3.4文档页面上找到文档和示例。

Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in Functional API. To define an enumeration, subclass Enum as follows:

枚举是使用类语法创建的,这使得它们易于阅读和编写。在函数API中描述了另一种创建方法。要定义一个枚举,子类枚举如下:

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

#19


10  

I have had occasion to need of an Enum class, for the purpose of decoding a binary file format. The features I happened to want is concise enum definition, the ability to freely create instances of the enum by either integer value or string, and a useful representation. Here's what I ended up with:

我有机会需要一个Enum类,以解码二进制文件格式。我所需要的特性是简洁的enum定义,可以*地通过整数值或字符串创建枚举的实例,以及一个有用的表示。以下是我的结论:

>>> 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
... 

A whimsical example of using it:

一个异想天开的例子:

>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
... 
>>> Citrus.Lemon
Citrus.Lemon
>>> 
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", 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

Key features:

主要特点:

  • str(), int() and repr() all produce the most useful output possible, respectively the name of the enumartion, its integer value, and a Python expression that evaluates back to the enumeration.
  • str()、int()和repr()都可以生成最有用的输出,分别是enumartion的名称、它的整数值,以及计算返回到枚举的Python表达式。
  • Enumerated values returned by the constructor are limited strictly to the predefined values, no accidental enum values.
  • 构造函数返回的枚举值严格限制在预定义值中,没有意外枚举值。
  • Enumerated values are singletons; they can be strictly compared with is
  • 枚举值是单身;它们可以严格地与is进行比较。

#20


9  

Keep it simple:

保持简单:

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

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

Then:

然后:

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

#21


8  

I really like Alec Thomas' solution (http://*.com/a/1695250):

我非常喜欢亚历克·托马斯的解决方案(http://*.com/a/1695250):

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

It's elegant and clean looking, but it's just a function that creates a class with the specified attributes.

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

With a little modification to the function, we can get it to act a little more 'enumy':

只要稍微修改一下这个函数,我们就可以让它的作用更小一些。

NOTE: I created the following examples by trying to reproduce the behavior of pygtk's new style 'enums' (like Gtk.MessageType.WARNING)

注意:我创建了以下示例,试图复制pygtk的新样式“enums”的行为(如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

This creates an enum based off a specified type. In addition to giving attribute access like the previous function, it behaves as you would expect an Enum to with respect to types. It also inherits the base class.

这将创建一个基于指定类型的枚举。除了像前面的函数那样提供属性访问,它的行为就像您期望的枚举类型一样。它还继承基类。

For example, integer enums:

例如,整数枚举:

>>> 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

Another interesting thing that can be done with this method is customize specific behavior by overriding built-in methods:

另一件有趣的事情可以用这个方法来完成,通过覆盖内置的方法定制特定的行为:

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'

#22


7  

The new standard in Python is PEP 435, so an Enum class will be available in future versions of Python:

Python中的新标准是PEP 435,因此在Python的将来版本中可以使用Enum类:

>>> from enum import Enum

However to begin using it now you can install the original library that motivated the PEP:

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

#sudo pip install flufl.enum   //or #sudo easy_install flufl.enum

Then you can use it as per its online guide:

然后你可以根据它的在线指南使用它:

>>> 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

#23


7  

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

If you name it, is your problem, but if not creating objects instead of values allows you to do this:

如果您将其命名为您的问题,但是如果不创建对象而不是值,您可以这样做:

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

When using other implementations sited here (also when using named instances in my example) you must be sure you never try to compare objects from different enums. For here's a possible pitfall:

当在这里使用其他实现时(也在我的示例中使用命名实例时),您必须确定您从不尝试比较不同枚举的对象。这里有一个可能的陷阱:

>>> 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

Yikes!

呵!

#24


5  

Alexandru's suggestion of using class constants for enums works quite well.

Alexandru关于使用类常量的建议非常有效。

I also like to add a dictionary for each set of constants to lookup a human-readable string representation.

我还喜欢为每组常量添加一个字典,以查找可读的字符串表示。

This serves two purposes: a) it provides a simple way to pretty-print your enum and b) the dictionary logically groups the constants so that you can test for membership.

它提供了两个目的: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())

#25


5  

The enum package from PyPI provides a robust implementation of enums. An earlier answer mentioned PEP 354; this was rejected but the proposal was implemented http://pypi.python.org/pypi/enum.

PyPI的enum包提供了对枚举的健壮实现。前面的回答提到了PEP 354;这是被拒绝的,但是这个建议被实现了:http://pypi.python.org/pypi/enum。

Usage is easy and elegant:

使用方便、优雅:

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

#26


3  

Here is a variant on Alec Thomas's solution:

下面是亚历克·托马斯解决方案的一个变体:

def enum(*args, **kwargs):
    return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs)) 

x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1

#27


3  

This solution is a simple way of getting a class for the enumeration defined as a list (no more annoying integer assignments):

这个解决方案是一个简单的方法,为枚举定义为一个列表(没有更烦人的整数分配):

enumeration.py:

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:

example.py:

import enumeration

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

#28


3  

While the original enum proposal, PEP 354, was rejected years ago, it keeps coming back up. Some kind of enum was intended to be added to 3.2, but it got pushed back to 3.3 and then forgotten. And now there's a PEP 435 intended for inclusion in Python 3.4. The reference implementation of PEP 435 is flufl.enum.

虽然最初的enum提案,PEP 354,在几年前被否决了,但它一直在恢复。某些类型的enum原本打算被添加到3.2,但它被推迟到了3.3,然后被遗忘。现在有一个用于在Python 3.4中包含的PEP 435。PEP 435的参考实现是flufl.enum。

As of April 2013, there seems to be a general consensus that something should be added to the standard library in 3.4—as long as people can agree on what that "something" should be. That's the hard part. See the threads starting here and here, and a half dozen other threads in the early months of 2013.

截至2013年4月,似乎有一种普遍的共识,那就是应该在标准库中添加一些东西,只要人们能够就“某件事”达成一致。这是最难的部分。在2013年的最初几个月里,看看这里和这里的线程,以及其他六个线程。

Meanwhile, every time this comes up, a slew of new designs and implementations appear on PyPI, ActiveState, etc., so if you don't like the FLUFL design, try a PyPI search.

与此同时,每当出现这种情况时,PyPI、ActiveState等都会出现大量新的设计和实现,因此,如果您不喜欢FLUFL设计,可以尝试PyPI搜索。

#29


3  

Here's an approach with some different characteristics I find valuable:

这里有一个方法,有一些不同的特点,我觉得有价值:

  • allows > and < comparison based on order in enum, not lexical order
  • 允许>和 <根据enum的顺序进行比较,而不是词法顺序。< li>
  • can address item by name, property or index: x.a, x['a'] or x[0]
  • 可以通过名称、属性或索引来处理项目:x。a,x[a]或[0]
  • supports slicing operations like [:] or [-1]
  • 支持切片操作,如[:]或[-1]

and most importantly prevents comparisons between enums of different types!

最重要的是防止不同类型的枚举之间的比较!

Based closely on http://code.activestate.com/recipes/413486-first-class-enums-in-python.

紧密地基于http://code.activestate.com/recipes/413486-first-class-enums-in-python。

Many doctests included here to illustrate what's different about this approach.

这里包含许多doctest来说明这种方法的不同之处。

def enum(*names):
    """
SYNOPSIS
    Well-behaved enumerated type, easier than creating custom classes

DESCRIPTION
    Create a custom type that implements an enumeration.  Similar in concept
    to a C enum but with some additional capabilities and protections.  See
    http://code.activestate.com/recipes/413486-first-class-enums-in-python/.

PARAMETERS
    names       Ordered list of names.  The order in which names are given
                will be the sort order in the enum type.  Duplicate names
                are not allowed.  Unicode names are mapped to ASCII.

RETURNS
    Object of type enum, with the input names and the enumerated values.

EXAMPLES
    >>> letters = enum('a','e','i','o','u','b','c','y','z')
    >>> letters.a < letters.e
    True

    ## index by property
    >>> letters.a
    a

    ## index by position
    >>> letters[0]
    a

    ## index by name, helpful for bridging string inputs to enum
    >>> letters['a']
    a

    ## sorting by order in the enum() create, not character value
    >>> letters.u < letters.b
    True

    ## normal slicing operations available
    >>> letters[-1]
    z

    ## error since there are not 100 items in enum
    >>> letters[99]
    Traceback (most recent call last):
        ...
    IndexError: tuple index out of range

    ## error since name does not exist in enum
    >>> letters['ggg']
    Traceback (most recent call last):
        ...
    ValueError: tuple.index(x): x not in tuple

    ## enums must be named using valid Python identifiers
    >>> numbers = enum(1,2,3,4)
    Traceback (most recent call last):
        ...
    AssertionError: Enum values must be string or unicode

    >>> a = enum('-a','-b')
    Traceback (most recent call last):
        ...
    TypeError: Error when calling the metaclass bases
        __slots__ must be identifiers

    ## create another enum
    >>> tags = enum('a','b','c')
    >>> tags.a
    a
    >>> letters.a
    a

    ## can't compare values from different enums
    >>> letters.a == tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    >>> letters.a < tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    ## can't update enum after create
    >>> letters.a = 'x'
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'a' is read-only

    ## can't update enum after create
    >>> del letters.u
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'u' is read-only

    ## can't have non-unique enum values
    >>> x = enum('a','b','c','a')
    Traceback (most recent call last):
        ...
    AssertionError: Enums must not repeat values

    ## can't have zero enum values
    >>> x = enum()
    Traceback (most recent call last):
        ...
    AssertionError: Empty enums are not supported

    ## can't have enum values that look like special function names
    ## since these could collide and lead to non-obvious errors
    >>> x = enum('a','b','c','__cmp__')
    Traceback (most recent call last):
        ...
    AssertionError: Enum values beginning with __ are not supported

LIMITATIONS
    Enum values of unicode type are not preserved, mapped to ASCII instead.

    """
    ## must have at least one enum value
    assert names, 'Empty enums are not supported'
    ## enum values must be strings
    assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
        isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
    ## enum values must not collide with special function names
    assert len([i for i in names if i.startswith("__")]) == 0,\
        'Enum values beginning with __ are not supported'
    ## each enum value must be unique from all others
    assert names == uniquify(names), 'Enums must not repeat values'

    class EnumClass(object):
        """ See parent function for explanation """

        __slots__ = names

        def __iter__(self):
            return iter(constants)

        def __len__(self):
            return len(constants)

        def __getitem__(self, i):
            ## this makes xx['name'] possible
            if isinstance(i, types.StringTypes):
                i = names.index(i)
            ## handles the more normal xx[0]
            return constants[i]

        def __repr__(self):
            return 'enum' + str(names)

        def __str__(self):
            return 'enum ' + str(constants)

        def index(self, i):
            return names.index(i)

    class EnumValue(object):
        """ See parent function for explanation """

        __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):
            assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
            return cmp(self.value, other.value)

        def __invert__(self):
            return constants[maximum - self.value]

        def __nonzero__(self):
            ## return bool(self.value)
            ## Original code led to bool(x[0])==False, not correct
            return True

        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

#30


2  

I had need of some symbolic constants in pyparsing to represent left and right associativity of binary operators. I used class constants like this:

在py解析中,我需要一些符号常量来表示二元运算符的左和右结合性。我用了这样的类常数:

# 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()

Now when client code wants to use these constants, they can import the entire enum using:

现在,当客户端代码想要使用这些常量时,它们可以使用:

import opAssoc from pyparsing

The enumerations are unique, they can be tested with 'is' instead of '==', they don't take up a big footprint in my code for a minor concept, and they are easily imported into the client code. They don't support any fancy str() behavior, but so far that is in the YAGNI category.

枚举是唯一的,它们可以用“is”来测试,而不是“==”,它们在我的代码中不占用一个小的概念,它们很容易被导入到客户机代码中。它们不支持任何奇特的str()行为,但到目前为止,它属于YAGNI类别。

#1


2262  

Enums have been added to Python 3.4 as described in PEP 435. It has also been backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 on pypi.

Enums被添加到Python 3.4中,正如PEP 435中所描述的那样。在pypi上,它还被反向移植到3.3、3.2、3.1、2.7、2.6、2.5和2.4。

For more advanced Enum techniques try the aenum library (2.7, 3.3+, same author as enum34. Code is not perfectly compatible between py2 and py3, e.g. you'll need __order__ in python 2).

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

  • To use enum34, do $ pip install enum34
  • 要使用enum34,请使用$ pip安装enum34。
  • To use aenum, do $ pip install aenum
  • 要使用枚举,请执行$ pip安装aenum。

Installing enum (no numbers) will install a completely different and incompatible version.

安装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: 1>
Animal['ant']  # returns <Animal.ant: 1> (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

or equivalently:

或者说:

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

In earlier versions, one way of accomplishing enums is:

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

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

which is used like so:

它是这样使用的:

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

You can also easily support automatic enumeration with something like this:

您还可以轻松地支持自动枚举,例如:

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

and used like so:

并使用如下所示:

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

Support for converting the values back to names can be added this way:

支持将值转换回名称可以这样添加:

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)

This overwrites anything with that name, but it is useful for rendering your enums in output. It will throw KeyError if the reverse mapping doesn't exist. With the first example:

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

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

#2


704  

Before PEP 435, Python didn't have an equivalent but you could implement your own.

在PEP 435之前,Python没有类似的功能,但是您可以实现自己的。

Myself, I like keeping it simple (I've seen some horribly complex examples on the net), something like this ...

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

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum values are distinct from integers.

在Python 3.4 (PEP 435)中,您可以将Enum作为基类。这为您提供了一些额外的功能,在PEP中描述。例如,枚举值与整数不同。

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

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

If you don't want to type the values, use the following shortcut:

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

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

#3


294  

Here is one implementation:

这里是一个实现:

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

Here is its usage:

这是它的用法:

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

print(Animals.DOG)

#4


176  

If you need the numeric values, here's the quickest way:

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

dog, cat, rabbit = range(3)

In Python 3.x you can also add a starred placeholder at the end, which will soak up all the remaining values of the range in case you don't mind wasting memory and cannot count:

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

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

#5


117  

The best solution for you would depend on what you require from your fake enum.

对于您来说,最好的解决方案将取决于您在模拟枚举中所需要的内容。

Simple enum:

简单的枚举:

If you need the enum as only a list of names identifying different items, the solution by Mark Harrison (above) is great:

如果您需要枚举列表,只是一个标识不同项目的名称列表,那么Mark Harrison(上面)的解决方案很好:

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

Using a range also allows you to set any starting value:

使用范围也允许您设置任何起始值:

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

In addition to the above, if you also require that the items belong to a container of some sort, then embed them in a class:

此外,如果您还要求项目属于某种容器,那么将它们嵌入到类中:

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

To use the enum item, you would now need to use the container name and the item name:

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

stype = Stationery.Pen

Complex enum:

复杂的枚举:

For long lists of enum or more complicated uses of enum, these solutions will not suffice. You could look to the recipe by Will Ware for Simulating Enumerations in Python published in the Python Cookbook. An online version of that is available here.

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

More info:

更多信息:

PEP 354: Enumerations in Python has the interesting details of a proposal for enum in Python and why it was rejected.

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

#6


75  

The typesafe enum pattern which was used in Java pre-JDK 5 has a number of advantages. Much like in Alexandru's answer, you create a class and class level fields are the enum values; however, the enum values are instances of the class rather than small integers. This has the advantage that your enum values don't inadvertently compare equal to small integers, you can control how they're printed, add arbitrary methods if that's useful and make assertions using isinstance:

在Java jdk 5中使用的typesafe enum模式有很多优点。与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

A recent thread on python-dev pointed out there are a couple of enum libraries in the wild, including:

python-dev最近的一个帖子指出,在野生环境中有几个enum库,包括:

#7


52  

An Enum class can be a one-liner.

Enum类可以是一行程序。

class Enum(tuple): __getattr__ = tuple.index

How to use it (forward and reverse lookup, keys, values, items, etc.)

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

>>> 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


43  

Python doesn't have a built-in equivalent to enum, and other answers have ideas for implementing your own (you may also be interested in the over the top version in the Python cookbook).

Python没有一个内置的等效于enum,其他的答案有实现自己的想法(您可能也对Python cookbook中的*版本感兴趣)。

However, in situations where an enum would be called for in C, I usually end up just using simple strings: because of the way objects/attributes are implemented, (C)Python is optimized to work very fast with short strings anyway, so there wouldn't really be any performance benefit to using integers. To guard against typos / invalid values you can insert checks in selected places.

但是,在需要用C调用enum的情况下,我通常只使用简单的字符串:由于对象/属性的实现方式,(C)Python被优化为以短字符串快速工作,因此使用整数不会有任何性能好处。为了防止输入错误/无效值,您可以在选定的位置插入检查。

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

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

(One disadvantage compared to using a class is that you lose the benefit of autocomplete)

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

#9


43  

So, I agree. Let's not enforce type safety in Python, but I would like to protect myself from silly mistakes. So what do we think about this?

所以,我同意。让我们不要在Python中强制执行类型安全,但是我希望保护自己避免犯愚蠢的错误。我们怎么想呢?

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

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

It keeps me from value-collision in defining my enums.

它使我在定义我的枚举时避免了价值冲突。

>>> Animal.Cat
2

There's another handy advantage: really fast reverse lookups:

还有一个便利的优点:快速反向查找:

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

#10


29  

On 2013-05-10, Guido agreed to accept PEP 435 into the Python 3.4 standard library. This means that Python finally has builtin support for enumerations!

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

There is a backport available for Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4. It's on Pypi as enum34.

对于Python 3.3、3.2、3.1、2.7、2.6、2.5和2.4,有一个backport可用。它在Pypi上,如enum34。

Declaration:

声明:

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

Representation:

表示:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

Iteration:

迭代:

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

Programmatic access:

编程访问:

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

For more information, refer to the proposal. Official documentation will probably follow soon.

要了解更多信息,请参考建议。官方文件可能很快就会出台。

#11


28  

I prefer to define enums in Python like so:

我更喜欢用Python来定义枚举:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

It's more bug-proof than using integers since you don't have to worry about ensuring that the integers are unique (e.g. if you said Dog = 1 and Cat = 1 you'd be screwed).

它比使用整数更容易出错,因为您不必担心确保整数是唯一的(例如,如果您说Dog = 1和Cat = 1,您就会被搞糊涂了)。

It's more bug-proof than using strings since you don't have to worry about typos (e.g. x == "catt" fails silently, but x == Animal.Catt is a runtime exception).

它比使用字符串更能防止bug,因为您不必担心拼写错误(例如,x == "catt"会在沉默中失败,但是x ==动物)。Catt是一个运行时异常。

#12


28  

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()

Use it like this:

使用它是这样的:

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

if you just want unique symbols and don't care about the values, replace this line:

如果你只是想要唯一的符号,而不关心这些值,就替换这条线:

__metaclass__ = M_add_class_attribs(enumerate(names))

with this:

用这个:

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

#13


20  

Another, very simple, implementation of an enum in Python, using namedtuple:

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

from collections import namedtuple

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

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

or, alternatively,

,或者

# 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())

Like the method above that subclasses set, this allows:

类似于子类设置的方法,它允许:

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

But has more flexibility as it can have different keys and values. This allows

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

MyEnum.FOO < MyEnum.BAR

to act as is expected if you use the version that fills in sequential number values.

如果您使用填充了顺序编号值的版本,则可以按照预期的方式行事。

#14


18  

Hmmm... I suppose the closest thing to an enum would be a dictionary, defined either like this:

嗯…我认为最接近enum的是一本字典,它的定义是这样的:

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

or

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

Then, you can use the symbolic name for the constants like this:

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

mymonth = months['January']

There are other options, like a list of tuples, or a tuple of tuples, but the dictionary is the only one that provides you with a "symbolic" (constant string) way to access the value.

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

Edit: I like Alexandru's answer too!

编辑:我也喜欢Alexandru的答案!

#15


16  

What I use:

我使用:

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

How to use:

如何使用:

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

So this gives you integer constants like state.PUBLISHED and the two-tuples to use as choices in Django models.

这就得到了像状态一样的整型常数。已发布和两元组作为Django模型的选择。

#16


14  

davidg recommends using dicts. I'd go one step further and use sets:

davidg建议使用字典。我将更进一步,使用集合:

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

Now you can test whether a value matches one of the values in the set like this:

现在您可以测试一个值是否与set中的值相匹配:

if m in months:

like dF, though, I usually just use string constants in place of enums.

像dF一样,我通常只使用字符串常量代替enums。

#17


13  

This is the best one I have seen: "First Class Enums in Python"

这是我见过的最好的一个:“Python中的第一个类枚举”

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

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

It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don't have any particular value; you can't use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can't use it as an integer, you can't use it as an integer by mistake so overall I think it is a win.) Each enum is a unique value. You can print enums, you can iterate over them, you can test that an enum value is "in" the enum. It's pretty complete and slick.

它给你一个类,这个类包含所有的枚举。枚举可以相互比较,但是没有任何特定的值;不能将其作为整数值使用。(一开始我反对这个,因为我习惯了C枚举,它是整数值。但是如果你不能把它作为一个整数来使用,你不能把它当作一个整数来使用,所以总的来说,我认为它是一个胜利。每个enum都是一个独特的值。您可以打印枚举,您可以迭代它们,您可以测试枚举值“在”枚举中。它非常完整和光滑。

Edit (cfi): The above link is not Python 3 compatible. Here's my port of enum.py to Python 3:

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

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)

#18


13  

From Python 3.4 there will be official support for enums. You can find documentation and examples here on Python 3.4 documentation page.

从Python 3.4中可以得到对enums的官方支持。您可以在Python 3.4文档页面上找到文档和示例。

Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in Functional API. To define an enumeration, subclass Enum as follows:

枚举是使用类语法创建的,这使得它们易于阅读和编写。在函数API中描述了另一种创建方法。要定义一个枚举,子类枚举如下:

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

#19


10  

I have had occasion to need of an Enum class, for the purpose of decoding a binary file format. The features I happened to want is concise enum definition, the ability to freely create instances of the enum by either integer value or string, and a useful representation. Here's what I ended up with:

我有机会需要一个Enum类,以解码二进制文件格式。我所需要的特性是简洁的enum定义,可以*地通过整数值或字符串创建枚举的实例,以及一个有用的表示。以下是我的结论:

>>> 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
... 

A whimsical example of using it:

一个异想天开的例子:

>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
... 
>>> Citrus.Lemon
Citrus.Lemon
>>> 
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", 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

Key features:

主要特点:

  • str(), int() and repr() all produce the most useful output possible, respectively the name of the enumartion, its integer value, and a Python expression that evaluates back to the enumeration.
  • str()、int()和repr()都可以生成最有用的输出,分别是enumartion的名称、它的整数值,以及计算返回到枚举的Python表达式。
  • Enumerated values returned by the constructor are limited strictly to the predefined values, no accidental enum values.
  • 构造函数返回的枚举值严格限制在预定义值中,没有意外枚举值。
  • Enumerated values are singletons; they can be strictly compared with is
  • 枚举值是单身;它们可以严格地与is进行比较。

#20


9  

Keep it simple:

保持简单:

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

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

Then:

然后:

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

#21


8  

I really like Alec Thomas' solution (http://*.com/a/1695250):

我非常喜欢亚历克·托马斯的解决方案(http://*.com/a/1695250):

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

It's elegant and clean looking, but it's just a function that creates a class with the specified attributes.

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

With a little modification to the function, we can get it to act a little more 'enumy':

只要稍微修改一下这个函数,我们就可以让它的作用更小一些。

NOTE: I created the following examples by trying to reproduce the behavior of pygtk's new style 'enums' (like Gtk.MessageType.WARNING)

注意:我创建了以下示例,试图复制pygtk的新样式“enums”的行为(如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

This creates an enum based off a specified type. In addition to giving attribute access like the previous function, it behaves as you would expect an Enum to with respect to types. It also inherits the base class.

这将创建一个基于指定类型的枚举。除了像前面的函数那样提供属性访问,它的行为就像您期望的枚举类型一样。它还继承基类。

For example, integer enums:

例如,整数枚举:

>>> 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

Another interesting thing that can be done with this method is customize specific behavior by overriding built-in methods:

另一件有趣的事情可以用这个方法来完成,通过覆盖内置的方法定制特定的行为:

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'

#22


7  

The new standard in Python is PEP 435, so an Enum class will be available in future versions of Python:

Python中的新标准是PEP 435,因此在Python的将来版本中可以使用Enum类:

>>> from enum import Enum

However to begin using it now you can install the original library that motivated the PEP:

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

#sudo pip install flufl.enum   //or #sudo easy_install flufl.enum

Then you can use it as per its online guide:

然后你可以根据它的在线指南使用它:

>>> 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

#23


7  

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

If you name it, is your problem, but if not creating objects instead of values allows you to do this:

如果您将其命名为您的问题,但是如果不创建对象而不是值,您可以这样做:

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

When using other implementations sited here (also when using named instances in my example) you must be sure you never try to compare objects from different enums. For here's a possible pitfall:

当在这里使用其他实现时(也在我的示例中使用命名实例时),您必须确定您从不尝试比较不同枚举的对象。这里有一个可能的陷阱:

>>> 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

Yikes!

呵!

#24


5  

Alexandru's suggestion of using class constants for enums works quite well.

Alexandru关于使用类常量的建议非常有效。

I also like to add a dictionary for each set of constants to lookup a human-readable string representation.

我还喜欢为每组常量添加一个字典,以查找可读的字符串表示。

This serves two purposes: a) it provides a simple way to pretty-print your enum and b) the dictionary logically groups the constants so that you can test for membership.

它提供了两个目的: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())

#25


5  

The enum package from PyPI provides a robust implementation of enums. An earlier answer mentioned PEP 354; this was rejected but the proposal was implemented http://pypi.python.org/pypi/enum.

PyPI的enum包提供了对枚举的健壮实现。前面的回答提到了PEP 354;这是被拒绝的,但是这个建议被实现了:http://pypi.python.org/pypi/enum。

Usage is easy and elegant:

使用方便、优雅:

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

#26


3  

Here is a variant on Alec Thomas's solution:

下面是亚历克·托马斯解决方案的一个变体:

def enum(*args, **kwargs):
    return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs)) 

x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1

#27


3  

This solution is a simple way of getting a class for the enumeration defined as a list (no more annoying integer assignments):

这个解决方案是一个简单的方法,为枚举定义为一个列表(没有更烦人的整数分配):

enumeration.py:

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:

example.py:

import enumeration

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

#28


3  

While the original enum proposal, PEP 354, was rejected years ago, it keeps coming back up. Some kind of enum was intended to be added to 3.2, but it got pushed back to 3.3 and then forgotten. And now there's a PEP 435 intended for inclusion in Python 3.4. The reference implementation of PEP 435 is flufl.enum.

虽然最初的enum提案,PEP 354,在几年前被否决了,但它一直在恢复。某些类型的enum原本打算被添加到3.2,但它被推迟到了3.3,然后被遗忘。现在有一个用于在Python 3.4中包含的PEP 435。PEP 435的参考实现是flufl.enum。

As of April 2013, there seems to be a general consensus that something should be added to the standard library in 3.4—as long as people can agree on what that "something" should be. That's the hard part. See the threads starting here and here, and a half dozen other threads in the early months of 2013.

截至2013年4月,似乎有一种普遍的共识,那就是应该在标准库中添加一些东西,只要人们能够就“某件事”达成一致。这是最难的部分。在2013年的最初几个月里,看看这里和这里的线程,以及其他六个线程。

Meanwhile, every time this comes up, a slew of new designs and implementations appear on PyPI, ActiveState, etc., so if you don't like the FLUFL design, try a PyPI search.

与此同时,每当出现这种情况时,PyPI、ActiveState等都会出现大量新的设计和实现,因此,如果您不喜欢FLUFL设计,可以尝试PyPI搜索。

#29


3  

Here's an approach with some different characteristics I find valuable:

这里有一个方法,有一些不同的特点,我觉得有价值:

  • allows > and < comparison based on order in enum, not lexical order
  • 允许>和 <根据enum的顺序进行比较,而不是词法顺序。< li>
  • can address item by name, property or index: x.a, x['a'] or x[0]
  • 可以通过名称、属性或索引来处理项目:x。a,x[a]或[0]
  • supports slicing operations like [:] or [-1]
  • 支持切片操作,如[:]或[-1]

and most importantly prevents comparisons between enums of different types!

最重要的是防止不同类型的枚举之间的比较!

Based closely on http://code.activestate.com/recipes/413486-first-class-enums-in-python.

紧密地基于http://code.activestate.com/recipes/413486-first-class-enums-in-python。

Many doctests included here to illustrate what's different about this approach.

这里包含许多doctest来说明这种方法的不同之处。

def enum(*names):
    """
SYNOPSIS
    Well-behaved enumerated type, easier than creating custom classes

DESCRIPTION
    Create a custom type that implements an enumeration.  Similar in concept
    to a C enum but with some additional capabilities and protections.  See
    http://code.activestate.com/recipes/413486-first-class-enums-in-python/.

PARAMETERS
    names       Ordered list of names.  The order in which names are given
                will be the sort order in the enum type.  Duplicate names
                are not allowed.  Unicode names are mapped to ASCII.

RETURNS
    Object of type enum, with the input names and the enumerated values.

EXAMPLES
    >>> letters = enum('a','e','i','o','u','b','c','y','z')
    >>> letters.a < letters.e
    True

    ## index by property
    >>> letters.a
    a

    ## index by position
    >>> letters[0]
    a

    ## index by name, helpful for bridging string inputs to enum
    >>> letters['a']
    a

    ## sorting by order in the enum() create, not character value
    >>> letters.u < letters.b
    True

    ## normal slicing operations available
    >>> letters[-1]
    z

    ## error since there are not 100 items in enum
    >>> letters[99]
    Traceback (most recent call last):
        ...
    IndexError: tuple index out of range

    ## error since name does not exist in enum
    >>> letters['ggg']
    Traceback (most recent call last):
        ...
    ValueError: tuple.index(x): x not in tuple

    ## enums must be named using valid Python identifiers
    >>> numbers = enum(1,2,3,4)
    Traceback (most recent call last):
        ...
    AssertionError: Enum values must be string or unicode

    >>> a = enum('-a','-b')
    Traceback (most recent call last):
        ...
    TypeError: Error when calling the metaclass bases
        __slots__ must be identifiers

    ## create another enum
    >>> tags = enum('a','b','c')
    >>> tags.a
    a
    >>> letters.a
    a

    ## can't compare values from different enums
    >>> letters.a == tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    >>> letters.a < tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    ## can't update enum after create
    >>> letters.a = 'x'
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'a' is read-only

    ## can't update enum after create
    >>> del letters.u
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'u' is read-only

    ## can't have non-unique enum values
    >>> x = enum('a','b','c','a')
    Traceback (most recent call last):
        ...
    AssertionError: Enums must not repeat values

    ## can't have zero enum values
    >>> x = enum()
    Traceback (most recent call last):
        ...
    AssertionError: Empty enums are not supported

    ## can't have enum values that look like special function names
    ## since these could collide and lead to non-obvious errors
    >>> x = enum('a','b','c','__cmp__')
    Traceback (most recent call last):
        ...
    AssertionError: Enum values beginning with __ are not supported

LIMITATIONS
    Enum values of unicode type are not preserved, mapped to ASCII instead.

    """
    ## must have at least one enum value
    assert names, 'Empty enums are not supported'
    ## enum values must be strings
    assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
        isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
    ## enum values must not collide with special function names
    assert len([i for i in names if i.startswith("__")]) == 0,\
        'Enum values beginning with __ are not supported'
    ## each enum value must be unique from all others
    assert names == uniquify(names), 'Enums must not repeat values'

    class EnumClass(object):
        """ See parent function for explanation """

        __slots__ = names

        def __iter__(self):
            return iter(constants)

        def __len__(self):
            return len(constants)

        def __getitem__(self, i):
            ## this makes xx['name'] possible
            if isinstance(i, types.StringTypes):
                i = names.index(i)
            ## handles the more normal xx[0]
            return constants[i]

        def __repr__(self):
            return 'enum' + str(names)

        def __str__(self):
            return 'enum ' + str(constants)

        def index(self, i):
            return names.index(i)

    class EnumValue(object):
        """ See parent function for explanation """

        __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):
            assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
            return cmp(self.value, other.value)

        def __invert__(self):
            return constants[maximum - self.value]

        def __nonzero__(self):
            ## return bool(self.value)
            ## Original code led to bool(x[0])==False, not correct
            return True

        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

#30


2  

I had need of some symbolic constants in pyparsing to represent left and right associativity of binary operators. I used class constants like this:

在py解析中,我需要一些符号常量来表示二元运算符的左和右结合性。我用了这样的类常数:

# 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()

Now when client code wants to use these constants, they can import the entire enum using:

现在,当客户端代码想要使用这些常量时,它们可以使用:

import opAssoc from pyparsing

The enumerations are unique, they can be tested with 'is' instead of '==', they don't take up a big footprint in my code for a minor concept, and they are easily imported into the client code. They don't support any fancy str() behavior, but so far that is in the YAGNI category.

枚举是唯一的,它们可以用“is”来测试,而不是“==”,它们在我的代码中不占用一个小的概念,它们很容易被导入到客户机代码中。它们不支持任何奇特的str()行为,但到目前为止,它属于YAGNI类别。