我如何在Python中表示'Enum'?



Answers

在PEP 435之前,Python沒有相同的功能,但可以實現自己的功能。

我自己,我喜歡保持簡單(我在網上看到過一些非常複雜的例子),像這樣的...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

在Python 3.4( PEP 435 )中,可以使Enum成為基類。 這可以讓你獲得一些額外的功能,如PEP所述。 例如,枚舉值不同於整數。

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

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

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

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

我主要是一名C#開發人員,但我目前正在使用Python開發一個項目。

我如何表示Python中Enum的等價物?




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

像這樣使用它:

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

如果你只是想要獨特的符號而不關心這些值,請替換這一行:

__metaclass__ = M_add_class_attribs(enumerate(names))

有了這個:

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



Python沒有內置的enum等價物,其他答案有實現你自己的想法(你也可能對Python食譜中here感興趣)。

然而,在C中需要enum情況下,我通常最終只使用簡單的字符串 :由於實現對象/屬性的方式,(C)Python優化後可以快速處理短字符串,所以在那裡對於使用整數不會有任何性能好處。 為了防止輸入錯誤/無效值,您可以在選定的位置插入檢查。

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

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

(與使用類相比,一個缺點是您失去了自動完成的好處)




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

# 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

枚舉是獨一無二的,它們可以用'is'代替'=='進行測試,它們在我的代碼中佔用很小的概念,並且很容易導入到客戶端代碼中。他們不支持任何花哨的str()行為,但是到目前為止,這在YAGNI類中。




這是亞歷克托馬斯解決方案的一個變種:

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



把事情簡單化:

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

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

然後:

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



從Python 3.4開始,官方會支持枚舉。 您可以在Python 3.4文檔頁面上找到文檔和示例。

枚舉是使用類語法創建的,這使得它們易於讀取和寫入。 Functional API中介紹了另一種創建方法。 要定義枚舉,Enum的子類如下所示:

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



嗯......我想最接近枚舉的是一個字典,定義如下:

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

要么

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

然後,你可以使用像這樣的常量的符號名稱:

mymonth = months['January']

還有其他選項,如元組列表或元組元組,但字典是唯一一個為您提供“符號”(常量字符串)方式來訪問該值的方法。

編輯:我也喜歡Alexandru的回答!




在2013-05-10,Guido同意接受PEP 435進入Python 3.4標準庫。 這意味著Python最終支持枚舉!

有一個可用於Python 3.3,3.2,3.1,2.7,2.6,2.5和2.4的backport。 它在Pypi上是enum34

宣言:

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

表示:

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

迭代:

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

程序化訪問:

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

有關更多信息,請參閱提案 。 官方文件可能會很快出台。




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 .

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.

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 .




JDK 5以前版本中使用的類型安全枚舉模式具有許多優點。 就像亞歷山德魯的回答一樣,你創建一個類和類級別字段是枚舉值; 然而,枚舉值是類的實例,而不是小整數。 這樣做的好處是你的枚舉值不會無意中等於小整數,你可以控制它們的打印方式,如果有用的話添加任意方法並使用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最近的一篇文章指出,在野外有兩個枚舉庫,包括:




亞歷山德魯建議使用類常量進行枚舉的工作很好。

我還想為每組常量添加一個字典來查找可讀的字符串表示。

這有兩個目的: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())



Python中的新標準是PEP 435 ,因此Enum類將在未來版本的Python中可用:

>>> from enum import Enum

但是現在開始使用它可以安裝激發PEP的原始庫

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

然後您可以按照其在線指南使用它

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



達維建議使用字典。 我會更進一步,並使用集合:

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

現在您可以測試某個值是否與此集合中的某個值匹配,如下所示:

if m in months:

像dF,但是,我通常只是使用字符串常量來代替枚舉。




如果您需要數字值,以下是最快的方法:

dog, cat, rabbit = range(3)

在Python 3.x中,您還可以在末尾添加一個帶星號的佔位符,這將吸收範圍的所有剩餘值,以防您不介意浪費內存並且無法計數:

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





Related