Como posso representar um 'Enum' em Python?

votos
1k

Eu sou principalmente um desenvolvedor C #, mas estou trabalhando atualmente em um projeto em Python.

Como posso representar o equivalente a um Enum em Python?

Publicado 31/08/2008 em 16:55
fonte usuário
Em outras línguas...                            


43 respostas

votos
2k

Enumerações foram adicionados ao pitão 3,4 como descrito no PEP 435 . Também tem sido portadas para 3,3, 3,2, 3,1, 2,7, 2,6, 2,5, e 2,4 no pypi.

Para técnicas Enumerar mais avançados experimentar a biblioteca aenum (2.7, 3.3+, mesmo autor enum34. O código não é perfeitamente compatível entre PY2 e PY3, por exemplo, você vai precisar __order__em python 2 ).

  • Para utilizar enum34, fazer$ pip install enum34
  • Para utilizar aenum, fazer$ pip install aenum

Instalando enum(sem números) vai instalar uma versão completamente diferente e incompatível.


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)

ou equivalente:

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

Em versões anteriores, uma forma de enums realizando é:

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

que é usado da seguinte forma:

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

Você também pode facilmente suportar a enumeração automática com algo como isto:

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

e usado assim:

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

Suporte para converter os valores de volta para nomes podem ser adicionados desta forma:

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)

Isso substitui qualquer coisa com esse nome, mas é útil para a prestação de seus enums na saída. Ele vai jogar KeyError se o mapeamento inverso não existe. Com o primeiro exemplo:

>>> Numbers.reverse_mapping['three']
'THREE'
Respondeu 08/11/2009 em 04:15
fonte usuário

votos
711

Antes de PEP 435, Python não tem um equivalente, mas você pode implementar seu próprio.

Eu mesmo, eu gosto de manter as coisas simples (Eu vi alguns exemplos terrivelmente complexas na rede), algo assim ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

Em Python 3.4 ( PEP 435 ), você pode fazer Enum a classe base. Isso faz com que você um pouco de funcionalidade extra, descrito no PEP. Por exemplo, os valores de enumeração são distintos dos números inteiros.

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

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

Se você não deseja digitar os valores, use o seguinte atalho:

class Animal(Enum):
    DOG, CAT = range(2)
Respondeu 31/08/2008 em 17:06
fonte usuário

votos
296

Aqui está uma implementação:

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

Aqui é o seu uso:

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

print(Animals.DOG)
Respondeu 02/02/2010 em 08:21
fonte usuário

votos
180

Se você precisar os valores numéricos, aqui é a maneira mais rápida:

dog, cat, rabbit = range(3)

Em Python 3.x você também pode adicionar um espaço reservado estrelou no final, que irá absorver todos os valores restantes da gama no caso de você não se importa de perder a memória e não pode contar:

dog, cat, rabbit, horse, *_ = range(100)
Respondeu 31/08/2008 em 21:31
fonte usuário

votos
118

A melhor solução para você vai depender do que você precisar do seu falso enum .

enum simples:

Se você precisa do enumque apenas uma lista de nomes que identificam diferentes itens , a solução por Mark Harrison (acima) é grande:

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

Usando um rangetambém permite que você defina qualquer valor inicial :

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

Além do acima, se você também exigem que os itens pertencem a um recipiente de algum tipo, em seguida, incorporá-los em uma classe:

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

Para usar o item enum, agora você precisa usar o nome do contêiner e o nome do item:

stype = Stationery.Pen

enum Complex:

Para longas listas de enumeração ou usos mais complicados de enum, estas soluções não será suficiente. Você pode olhar para a receita por Will Ware para Simulando Enumerations em Python publicados no Python Cookbook . Uma versão online que está disponível aqui .

Mais informações:

PEP 354: Enumerations em Python tem os detalhes interessantes de uma proposta de enum em Python e por que foi rejeitado.

Respondeu 07/10/2009 em 03:47
fonte usuário

votos
75

O padrão typesafe enum que foi utilizado em Java pré-JDK 5 tem um número de vantagens. Bem como na resposta do Alexandru, você cria um nível de classe e classe campos são os valores enum; no entanto, os valores de enumeração são instâncias da classe em vez de números inteiros pequenos. Isto tem a vantagem de que seus valores enum não inadvertidamente comparar igual a pequenos números inteiros, você pode controlar como eles são impressos, adicione métodos arbitrários se isso é útil e fazer afirmações usando 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

Um recente thread na python-dev apontado há um par de bibliotecas enum em estado selvagem, incluindo:

Respondeu 01/09/2008 em 17:05
fonte usuário

votos
54

Uma classe Enum pode ser um one-liner.

class Enum(tuple): __getattr__ = tuple.index

Como usá-lo (frente e verso de pesquisa, chaves, valores, itens, 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)]
Respondeu 08/02/2012 em 21:59
fonte usuário

votos
43

Então, eu concordo. Não vamos impor a segurança de tipos em Python, mas eu gostaria de me proteger de erros bobos. Então, o que nós pensamos sobre isso?

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

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

Isso me impede de valor-colisão na definição meus enums.

>>> Animal.Cat
2

Há outra vantagem útil: muito rápido pesquisas inversas:

def name_of(self, i):
    return self.values[i]
Respondeu 04/11/2010 em 00:02
fonte usuário

votos
43

Python não tem um built-in equivalente a enum, e outras respostas têm idéias para implementar o seu próprio (você também pode estar interessado em relação à versão topo no livro de receitas Python).

No entanto, em situações em que um enumiria ser postos em C, eu geralmente acabam usando apenas cordas simples : por causa da maneira objetos / atributos são implementados, (C) Python é otimizado para trabalhar muito rápido com seqüências curtas de qualquer maneira, então não há wouldn 't realmente ser qualquer benefício de desempenho ao uso de números inteiros. Para se proteger contra erros de digitação valores / inválido você pode inserir verificações em locais selecionados.

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

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

(Uma desvantagem comparado ao uso de uma classe é que você perde o benefício de autocomplete)

Respondeu 31/08/2008 em 19:10
fonte usuário

votos
29

Em 2013/05/10, Guido concordou em aceitar PEP 435 na biblioteca padrão do Python 3.4. Isto significa que Python finalmente tem suporte nativo para enumerações!

Há um backport disponível para Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, e 2.4. Está na PyPI como enum34 .

Declaração:

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

Representação:

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

Iteração:

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

acesso programático:

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

Para mais informações, consulte a proposta . Documentação oficial, provavelmente, seguirá em breve.

Respondeu 10/05/2013 em 17:09
fonte usuário

votos
28

Eu prefiro definir enums em Python assim:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

É mais bug prova de que usando números inteiros desde que você não precisa se preocupar em garantir que os inteiros são únicos (por exemplo, se você disse Dog = 1 e Cat = 1 você estaria ferrado).

É mais bug prova de que usar cordas desde que você não precisa se preocupar com erros de digitação (por exemplo x == "catt" falha silenciosamente, mas x == Animal.Catt é uma exceção tempo de execução).

Respondeu 29/11/2010 em 03:05
fonte usuário

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

Usá-lo como este:

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

se você quiser apenas símbolos únicos e não se preocupam com os valores, substituir esta linha:

__metaclass__ = M_add_class_attribs(enumerate(names))

com isso:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)
Respondeu 20/09/2008 em 12:49
fonte usuário

votos
20

Outra, muito simples, a implementação de um enum em Python, usando namedtuple:

from collections import namedtuple

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

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

ou alternativamente,

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

Como o método acima que subclasses set, isto permite:

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

Mas tem mais flexibilidade, pois ele pode ter diferentes chaves e valores. Isso permite

MyEnum.FOO < MyEnum.BAR

para atuar como é esperado se você usar a versão que preenche valores de números seqüenciais.

Respondeu 07/08/2011 em 06:51
fonte usuário

votos
18

Hmmm ... Acho que a coisa mais próxima de uma enumeração seria um dicionário, definida quer como este:

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

ou

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

Então, você pode usar o nome simbólico para as constantes como este:

mymonth = months['January']

Há outras opções, como uma lista de tuplas, ou uma tupla de tuplas, mas o dicionário é o único que lhe fornece uma maneira "simbólica" (string constante) para acessar o valor.

Edit: Eu gosto de resposta de Alexandru também!

Respondeu 31/08/2008 em 17:09
fonte usuário

votos
16

O que eu uso:

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

Como usar:

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

Então, isso dá-lhe constantes inteiras como state.PUBLISHED e os dois tuplos para usar como escolhas em modelos Django.

Respondeu 03/02/2009 em 00:39
fonte usuário

votos
14

De Python 3.4, haverá suporte oficial para enums. Você pode encontrar documentação e exemplos aqui no Python 3.4 página de documentação .

Enumerações são criados usando a sintaxe classe, o que torna fácil de ler e escrever. Um método de criação alternativa é descrita na API funcional. Para definir uma enumeração, subclasse enum como se segue:

from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3
Respondeu 11/12/2013 em 14:49
fonte usuário

votos
14

davidg recomenda o uso dicts. Eu iria um passo além e usar conjuntos:

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

Agora você pode testar se um valor corresponde a um dos valores do conjunto como este:

if m in months:

como DF, porém, eu geralmente apenas usar constantes de cadeia no lugar de enums.

Respondeu 02/09/2008 em 04:20
fonte usuário

votos
13

Este é o melhor que eu já vi: "First Class Enums em Python"

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

Dá-lhe uma classe ea classe contém todos os enums. As enumerações podem ser comparados uns com os outros, mas não têm qualquer valor particular; você não pode usá-los como um valor inteiro. (Eu resisti esta em primeiro lugar, porque estou habituado a enums C, que são valores inteiros. Mas se você não pode usá-lo como um número inteiro, você não pode usá-lo como um número inteiro por engano assim, no geral eu acho que é uma vitória .) Cada enumeração é um valor único. Você pode imprimir enums, você pode iterar sobre eles, você pode testar se um valor de enumeração é "in" da enumeração. É muito completo e liso.

Edit (TPI): O link acima não é Python 3 compatível. Aqui é o meu porto de enum.py para 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)
Respondeu 18/11/2009 em 03:51
fonte usuário

votos
10

Mantenha simples:

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

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

Então:

DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1
Respondeu 28/03/2014 em 22:44
fonte usuário

votos
10

Eu tive ocasião de precisar de uma classe Enum, com a finalidade de decodificar um formato de arquivo binário. As características aconteceu de eu quero é definição enum concisa, a capacidade de criar livremente instâncias do enum por qualquer valor inteiro ou string, e uma útil representation. Aqui está o que eu acabei com:

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

Um exemplo peculiar de usá-lo:

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

Características principais:

  • str(), int()E repr()todas produzem a saída mais útil possível, respectivamente, o nome do enumartion, o seu valor de número inteiro, e uma expressão Python que avalia volta para a enumeração.
  • Os valores enumerados devolvidos pelo construtor se limitam estritamente aos valores pré-definidos, não há valores enum acidentais.
  • Os valores enumerados são únicos; eles podem ser rigorosamente em comparação comis
Respondeu 22/12/2011 em 03:16
fonte usuário

votos
8

Eu realmente gosto solução Alec Thomas' (http://stackoverflow.com/a/1695250):

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

É elegante e limpo procurando, mas é apenas uma função que cria uma classe com os atributos especificados.

Com uma pequena modificação para a função, podemos obtê-lo a agir um pouco mais 'enumy':

NOTA: Eu criei os seguintes exemplos, tentando reproduzir o comportamento de 'enums' do PyGtk novo estilo (como 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

Isso cria um enum baseado fora de um tipo especificado. Além de dar acesso a atributos como a função anterior, ele se comporta como seria de esperar um Enum com respeito aos tipos. Ele também herda a classe base.

Por exemplo, enumerações inteiros:

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

Outra coisa interessante que pode ser feito com este método é personalizar o comportamento específico, substituindo métodos embutidos:

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'
Respondeu 18/01/2012 em 07:09
fonte usuário

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

Se o nome dele, é o seu problema, mas se não a criação de objetos em vez de valores permite que você faça o seguinte:

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

Ao usar outras implementações localizadas aqui (também ao usar instâncias nomeadas no meu exemplo) você deve ter certeza que você nunca tentar comparar objetos de diferentes enums. Por aqui está uma possível armadilha:

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

Caramba!

Respondeu 11/11/2014 em 09:26
fonte usuário

votos
7

O novo padrão em Python é PEP 435 , então uma classe Enum estará disponível em versões futuras do Python:

>>> from enum import Enum

No entanto, para começar a usá-lo agora você pode instalar a biblioteca original que motivou o PEP:

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

Em seguida, você pode usá-lo como por seu guia on-line :

>>> 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
Respondeu 10/05/2013 em 17:22
fonte usuário

votos
5

O pacote de enumeração de PyPI fornece uma implementação robusta de enums. Uma resposta anteriormente mencionado PEP 354; este foi rejeitado, mas a proposta foi implementada http://pypi.python.org/pypi/enum .

O uso é fácil e elegante:

>>> 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'
Respondeu 16/03/2010 em 23:36
fonte usuário

votos
5

sugestão de usar as constantes de classe para enums do Alexandru funciona muito bem.

Eu também gostaria de adicionar um dicionário para cada conjunto de constantes para procurar uma representação string legível.

Isto serve a dois propósitos: a) que fornece uma maneira simples de bem-imprimir o enum e b) o dicionário logicamente grupos constantes de modo que você pode testar para a adesão.

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())
Respondeu 19/09/2008 em 04:37
fonte usuário

votos
3

Aqui está uma abordagem com algumas características diferentes que encontram valiosas:

  • permite> e <comparação com base na ordem em enum, não ordem lexical
  • pode abordar item, nome, propriedade ou índice: xa, x [ 'a'] ou x [0]
  • suporta operações que cortam como [:] ou [-1]

eo mais importante impede comparações entre enums de tipos diferentes !

Estreitamente baseado em http://code.activestate.com/recipes/413486-first-class-enums-in-python .

Muitos doctests incluído aqui para ilustrar o que é diferente sobre esta abordagem.

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
Respondeu 19/06/2013 em 22:30
fonte usuário

votos
3

Embora a proposta enum original, PEP 354 anos foi rejeitada atrás, ele mantém a voltar-se. Algum tipo de enumeração foi destinado a ser adicionado a 3,2, mas foi empurrado de volta para 3,3 e depois esquecido. E agora há um PEP 435 destina-se a inclusão no Python 3.4. A implementação de referência de PEP 435 é flufl.enum.

Em abril de 2013, parece haver um consenso geral de que algo deve ser adicionado à biblioteca padrão em 3.4, contanto que as pessoas podem concordar com o que esse "algo" deve ser. Essa é a parte mais difícil. Veja os tópicos começando aqui e aqui , e meia dúzia de outros tópicos nos primeiros meses de 2013.

Enquanto isso, cada vez que este vem para cima, uma série de novos projetos e implementações aparecer no PyPI, ActiveState, etc., por isso, se você não gosta do design FLUFL, tente uma pesquisa PyPI .

Respondeu 19/04/2013 em 02:16
fonte usuário

votos
3

Esta solução é uma maneira simples de conseguir uma classe para a enumeração definida como uma lista (sem atribuições inteiros mais irritantes):

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',
))
Respondeu 18/09/2011 em 02:26
fonte usuário

votos
3

Aqui está uma variante na solução de Alec Thomas :

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
Respondeu 14/06/2011 em 18:29
fonte usuário

votos
2

Aqui está uma boa Python receita que eu encontrei aqui: 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)()

Exemplo de Uso:

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

Mais detalhes podem ser encontrados na página da receita.

Respondeu 17/03/2014 em 18:34
fonte usuário

votos
2

não vi este na lista de respostas, aqui é o que eu chicoteado até. Ele permite o uso de 'em' palavra-chave e método len ():

class EnumTypeError(TypeError):
    pass

class Enum(object):
    """
    Minics enum type from different languages
    Usage:
    Letters = Enum(list('abc'))
    a = Letters.a
    print(a in Letters) # True
    print(54 in Letters) # False
    """
    def __init__(self, enums):
        if isinstance(enums, dict):
            self.__dict__.update(enums)
        elif isinstance(enums, list) or isinstance(enums, tuple):
            self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
        else:
            raise EnumTypeError

    def __contains__(self, key):
        return key in self.__dict__.values()

    def __len__(self):
        return len(self.__dict__.values())


if __name__ == '__main__':
    print('Using a dictionary to create Enum:')
    Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    print('\nUsing a list to create Enum:')
    Letters = Enum(list('abcde'))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    try:
        # make sure we raise an exception if we pass an invalid arg
        Failure = Enum('This is a Failure')
        print('Failure')
    except EnumTypeError:
        print('Success!')

Saída:

Using a dictionary to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5

Using a list to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5
Success!
Respondeu 05/09/2013 em 05:12
fonte usuário

votos
2

A solução que eu costumo usar é esta função simples para obter uma instância de uma classe criada dinamicamente.

def enum(names):
    "Create a simple enumeration having similarities to C."
    return type('enum', (), dict(map(reversed, enumerate(
        names.replace(',', ' ').split())), __slots__=()))()

Usá-lo é tão simples como chamar a função com uma corda ter os nomes que pretende fazer referência.

grade = enum('A B C D F')
state = enum('awake, sleeping, dead')

Os valores são apenas números inteiros, então você pode tirar vantagem de que, se desejado (assim como na linguagem C).

>>> grade.A
0
>>> grade.B
1
>>> grade.F == 4
True
>>> state.dead == 2
True
Respondeu 31/01/2013 em 15:27
fonte usuário

votos
2

Uma variante (com suporte para obter o nome de um valor de enumeração) para resposta puro de Alec Thomas :

class EnumBase(type):
    def __init__(self, name, base, fields):
        super(EnumBase, self).__init__(name, base, fields)
        self.__mapping = dict((v, k) for k, v in fields.iteritems())
    def __getitem__(self, val):
        return self.__mapping[val]

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

Numbers = enum(ONE=1, TWO=2, THREE='three')
print Numbers.TWO
print Numbers[Numbers.ONE]
print Numbers[2]
print Numbers['three']
Respondeu 21/06/2012 em 23:43
fonte usuário

votos
2

Por que enumerações ser ints? Infelizmente, eu não posso pensar em qualquer boa aparência construir para produzir isso sem alterar a linguagem Python, então eu vou usar strings:

class Enumerator(object):
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        if self.name == other:
            return True
        return self is other

    def __ne__(self, other):
        if self.name != other:
            return False
        return self is other

    def __repr__(self):
        return 'Enumerator({0})'.format(self.name)

    def __str__(self):
        return self.name

class Enum(object):
    def __init__(self, *enumerators):
        for e in enumerators:
            setattr(self, e, Enumerator(e))
    def __getitem__(self, key):
        return getattr(self, key)

Em seguida, novamente talvez seja ainda melhor agora que podemos naturalmente testar contra cordas, para o bem dos arquivos de configuração ou outra entrada remoto.

Exemplo:

class Cow(object):
    State = Enum(
        'standing',
        'walking',
        'eating',
        'mooing',
        'sleeping',
        'dead',
        'dying'
    )
    state = State.standing

In [1]: from enum import Enum

In [2]: c = Cow()

In [3]: c2 = Cow()

In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))

In [5]: c.state == c2.state
Out[5]: True

In [6]: c.State.mooing
Out[6]: Enumerator(mooing)

In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)

In [8]: c.state = Cow.State.dead

In [9]: c.state == c2.state
Out[9]: False

In [10]: c.state == Cow.State.dead
Out[10]: True

In [11]: c.state == 'dead'
Out[11]: True

In [12]: c.state == Cow.State['dead']
Out[11]: True
Respondeu 07/05/2010 em 03:05
fonte usuário

votos
2

Eu tinha necessidade de algumas constantes simbólicas em pyparsing para representar a esquerda e direita associatividade de operadores binários. Eu costumava constantes da classe como este:

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

Agora, quando o código do cliente quer usar essas constantes, eles podem importar todo o enum usando:

import opAssoc from pyparsing

As enumerações são únicos, eles podem ser testados com 'é' em vez de '==', eles não ocupam uma grande pegada no meu código para um conceito menor, e eles são facilmente importados para o código do cliente. Eles não suportam qualquer comportamento str fantasia (), mas até agora que está no YAGNI categoria.

Respondeu 17/11/2009 em 21:54
fonte usuário

votos
2

É engraçado, eu só tinha uma necessidade para este no outro dia e eu não poderia encontrar uma implementação pena usar ... então eu escrevi o meu próprio:

import functools

class EnumValue(object):
    def __init__(self,name,value,type):
        self.__value=value
        self.__name=name
        self.Type=type
    def __str__(self):
        return self.__name
    def __repr__(self):#2.6 only... so change to what ever you need...
        return '{cls}({0!r},{1!r},{2})'.format(self.__name,self.__value,self.Type.__name__,cls=type(self).__name__)

    def __hash__(self):
        return hash(self.__value)
    def __nonzero__(self):
        return bool(self.__value)
    def __cmp__(self,other):
        if isinstance(other,EnumValue):
            return cmp(self.__value,other.__value)
        else:
            return cmp(self.__value,other)#hopefully their the same type... but who cares?
    def __or__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} | {1.Name}'.format(self,other),self.Value|other.Value,self.Type)
    def __and__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} & {1.Name}'.format(self,other),self.Value&other.Value,self.Type)
    def __contains__(self,other):
        if self.Value==other.Value:
            return True
        return bool(self&other)
    def __invert__(self):
        enumerables=self.Type.__enumerables__
        return functools.reduce(EnumValue.__or__,(enum for enum in enumerables.itervalues() if enum not in self))

    @property
    def Name(self):
        return self.__name

    @property
    def Value(self):
        return self.__value

class EnumMeta(type):
    @staticmethod
    def __addToReverseLookup(rev,value,newKeys,nextIter,force=True):
        if value in rev:
            forced,items=rev.get(value,(force,()) )
            if forced and force: #value was forced, so just append
                rev[value]=(True,items+newKeys)
            elif not forced:#move it to a new spot
                next=nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,items,nextIter,False)
                rev[value]=(force,newKeys)
            else: #not forcing this value
                next = nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,newKeys,nextIter,False)
                rev[value]=(force,newKeys)
        else:#set it and forget it
            rev[value]=(force,newKeys)
        return value

    def __init__(cls,name,bases,atts):
        classVars=vars(cls)
        enums = classVars.get('__enumerables__',None)
        nextIter = getattr(cls,'__nextitr__',itertools.count)()
        reverseLookup={}
        values={}

        if enums is not None:
            #build reverse lookup
            for item in enums:
                if isinstance(item,(tuple,list)):
                    items=list(item)
                    value=items.pop()
                    EnumMeta.__addToReverseLookup(reverseLookup,value,tuple(map(str,items)),nextIter)
                else:
                    value=nextIter.next()
                    value=EnumMeta.__addToReverseLookup(reverseLookup,value,(str(item),),nextIter,False)#add it to the reverse lookup, but don't force it to that value

            #build values and clean up reverse lookup
            for value,fkeys in reverseLookup.iteritems():
                f,keys=fkeys
                for key in keys:
                    enum=EnumValue(key,value,cls)
                    setattr(cls,key,enum)
                    values[key]=enum
                reverseLookup[value]=tuple(val for val in values.itervalues() if val.Value == value)
        setattr(cls,'__reverseLookup__',reverseLookup)
        setattr(cls,'__enumerables__',values)
        setattr(cls,'_Max',max([key for key in reverseLookup] or [0]))
        return super(EnumMeta,cls).__init__(name,bases,atts)

    def __iter__(cls):
        for enum in cls.__enumerables__.itervalues():
            yield enum
    def GetEnumByName(cls,name):
        return cls.__enumerables__.get(name,None)
    def GetEnumByValue(cls,value):
        return cls.__reverseLookup__.get(value,(None,))[0]

class Enum(object):
    __metaclass__=EnumMeta
    __enumerables__=None

class FlagEnum(Enum):
    @staticmethod
    def __nextitr__():
        yield 0
        for val in itertools.count():
            yield 2**val

def enum(name,*args):
    return EnumMeta(name,(Enum,),dict(__enumerables__=args))

Tomá-lo ou deixá-lo, ele fez o que eu precisava para fazer :)

Use-o como:

class Air(FlagEnum):
    __enumerables__=('None','Oxygen','Nitrogen','Hydrogen')

class Mammals(Enum):
    __enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))
Respondeu 21/10/2008 em 03:08
fonte usuário

votos
1

Python 2,7 e find_name ()

Aqui é uma implementação fácil de ler da idéia escolhida com alguns métodos auxiliares, que talvez sejam mais Pythonic e mais limpo de usar do que "reverse_mapping". Requer Python> = 2,7.

Para abordar alguns comentários abaixo, Enums são bastante úteis para evitar erros de ortografia no código, por exemplo para máquinas de estado, classificadores de erro, etc.

def Enum(*sequential, **named):
  """Generate a new enum type. Usage example:

  ErrorClass = Enum('STOP','GO')
  print ErrorClass.find_name(ErrorClass.STOP)
    = "STOP"
  print ErrorClass.find_val("STOP")
    = 0
  ErrorClass.FOO     # Raises AttributeError
  """
  enums = { v:k for k,v in enumerate(sequential) } if not named else named

  @classmethod
  def find_name(cls, val):
    result = [ k for k,v in cls.__dict__.iteritems() if v == val ]
    if not len(result):
        raise ValueError("Value %s not found in Enum" % val)
    return result[0]

  @classmethod
  def find_val(cls, n):
    return getattr(cls, n)

  enums['find_val'] = find_val
  enums['find_name'] = find_name
  return type('Enum', (), enums)
Respondeu 08/04/2013 em 19:58
fonte usuário

votos
1

Eu gosto de usar listas ou conjuntos como enumerações. Por exemplo:

>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>
Respondeu 20/11/2012 em 14:18
fonte usuário

votos
1

Eu uso um metaclass para implementar uma enumeração (no meu pensamento, é uma const). Aqui está o código:

class ConstMeta(type):
    '''
    Metaclass for some class that store constants
    '''
    def __init__(cls, name, bases, dct):
        '''
        init class instance
        '''
        def static_attrs():
            '''
            @rtype: (static_attrs, static_val_set)
            @return: Static attributes in dict format and static value set
            '''
            import types
            attrs = {}
            val_set = set()
            #Maybe more
            filter_names = set(['__doc__', '__init__', '__metaclass__', '__module__', '__main__'])
            for key, value in dct.iteritems():
                if type(value) != types.FunctionType and key not in filter_names:
                    if len(value) != 2:
                        raise NotImplementedError('not support for values that is not 2 elements!')
                    #Check value[0] duplication.
                    if value[0] not in val_set:
                        val_set.add(value[0])
                    else:
                        raise KeyError("%s 's key: %s is duplicated!" % (dict([(key, value)]), value[0]))
                    attrs[key] = value
            return attrs, val_set

        attrs, val_set = static_attrs()
        #Set STATIC_ATTRS to class instance so that can reuse
        setattr(cls, 'STATIC_ATTRS', attrs)
        setattr(cls, 'static_val_set', val_set)
        super(ConstMeta, cls).__init__(name, bases, dct)

    def __getattribute__(cls, name):
        '''
        Rewrite the special function so as to get correct attribute value
        '''
        static_attrs = object.__getattribute__(cls, 'STATIC_ATTRS')
        if name in static_attrs:
            return static_attrs[name][0]
        return object.__getattribute__(cls, name)

    def static_values(cls):
        '''
        Put values in static attribute into a list, use the function to validate value.
        @return: Set of values
        '''
        return cls.static_val_set

    def __getitem__(cls, key):
        '''
        Rewrite to make syntax SomeConstClass[key] works, and return desc string of related static value.
        @return: Desc string of related static value
        '''
        for k, v in cls.STATIC_ATTRS.iteritems():
            if v[0] == key:
                return v[1]
        raise KeyError('Key: %s does not exists in %s !' % (str(key), repr(cls)))


class Const(object):
    '''
    Base class for constant class.

    @usage:

    Definition: (must inherit from Const class!
        >>> class SomeConst(Const):
        >>>   STATUS_NAME_1 = (1, 'desc for the status1')
        >>>   STATUS_NAME_2 = (2, 'desc for the status2')

    Invoke(base upper SomeConst class):
    1) SomeConst.STATUS_NAME_1 returns 1
    2) SomeConst[1] returns 'desc for the status1'
    3) SomeConst.STATIC_ATTRS returns {'STATUS_NAME_1': (1, 'desc for the status1'), 'STATUS_NAME_2': (2, 'desc for the status2')}
    4) SomeConst.static_values() returns set([1, 2])

    Attention:
    SomeCosnt's value 1, 2 can not be duplicated!
    If WrongConst is like this, it will raise KeyError:
    class WrongConst(Const):
        STATUS_NAME_1 = (1, 'desc for the status1')
        STATUS_NAME_2 = (1, 'desc for the status2')
    '''
    __metaclass__ = ConstMeta
##################################################################
#Const Base Class ends
##################################################################


def main():
    class STATUS(Const):
        ERROR = (-3, '??')
        OK = (0, '??')

    print STATUS.ERROR
    print STATUS.static_values()
    print STATUS.STATIC_ATTRS

    #Usage sample:
    user_input = 1
    #Validate input:
    print user_input in STATUS.static_values()
    #Template render like:
    print '<select>'
    for key, value in STATUS.STATIC_ATTRS.items():
        print '<option value="%s">%s</option>' % (value[0], value[1])
    print '</select>'


if __name__ == '__main__':
    main()
Respondeu 04/04/2012 em 03:43
fonte usuário

votos
1

Eu gosto do Java enum, que é como eu fazê-lo em 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()

o uso da amostra:

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

Todas as variáveis ​​de classe são definidos como uma tupla, assim como o construtor. Até agora, você não pode usar argumentos nomeados.

Respondeu 04/06/2010 em 17:33
fonte usuário

votos
1
def enum( *names ):

    '''
    Makes enum.
    Usage:
        E = enum( 'YOUR', 'KEYS', 'HERE' )
        print( E.HERE )
    '''

    class Enum():
        pass
    for index, name in enumerate( names ):
        setattr( Enum, name, index )
    return Enum
Respondeu 26/05/2010 em 14:14
fonte usuário

votos
1

Após o Java como enum implementação proposto por Aaron Mäenpää, eu saí com o seguinte. A idéia era torná-lo genérico e analisável.

class Enum:
    #'''
    #Java like implementation for enums.
    #
    #Usage:
    #class Tool(Enum): name = 'Tool'
    #Tool.DRILL = Tool.register('drill')
    #Tool.HAMMER = Tool.register('hammer')
    #Tool.WRENCH = Tool.register('wrench')
    #'''

    name = 'Enum'    # Enum name
    _reg = dict([])   # Enum registered values

    @classmethod
    def register(cls, value):
        #'''
        #Registers a new value in this enum.
        #
        #@param value: New enum value.
        #
        #@return: New value wrapper instance.
        #'''
        inst = cls(value)
        cls._reg[value] = inst
        return inst

    @classmethod
    def parse(cls, value):
        #'''
        #Parses a value, returning the enum instance.
        #
        #@param value: Enum value.
        #
        #@return: Value corresp instance.        
        #'''
        return cls._reg.get(value)    

    def __init__(self, value):
        #'''
        #Constructor (only for internal use).
        #'''
        self.value = value

    def __str__(self):
        #'''
        #str() overload.
        #'''
        return self.value

    def __repr__(self):
        #'''
        #repr() overload.
        #'''
        return "<" + self.name + ": " + self.value + ">"
Respondeu 05/03/2010 em 21:24
fonte usuário

votos
1

Use o seguinte.

TYPE = {'EAN13':   u'EAN-13',
        'CODE39':  u'Code 39',
        'CODE128': u'Code 128',
        'i25':     u'Interleaved 2 of 5',}

>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']

Eu usei isso para Django escolhas modelo, e parece muito pythônico. Não é realmente um Enum, mas ele faz o trabalho.

Respondeu 19/10/2009 em 11:21
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more