Sou principalmente desenvolvedor de C #, mas atualmente estou trabalhando em um projeto em Python.
Como posso representar o equivalente a um Enum em Python?
fonte
Sou principalmente desenvolvedor de C #, mas atualmente estou trabalhando em um projeto em Python.
Como posso representar o equivalente a um Enum em Python?
Enums foram adicionadas ao Python 3.4, conforme descrito no PEP 435 . Também foi portado para 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 e 2.4 no pypi.
Para técnicas Enum mais avançadas, tente 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ê precisará __order__
em python 2 ).
enum34
, faça$ pip install enum34
aenum
, faça$ pip install aenum
A instalação enum
(sem números) 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
Nas versões anteriores, uma maneira de realizar enumerações é:
def enum(**enums):
return type('Enum', (), enums)
que é usado assim:
>>> 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
O suporte para converter os valores novamente em nomes pode ser adicionado desta maneira:
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 renderizar suas enumerações na saída. Ele lançará KeyError se o mapeamento reverso não existir. Com o primeiro exemplo:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
) na função enum para versões mais antigas é oferecer suporte a valores personalizados:enum("blue", "red", "green", black=0)
Antes do PEP 435, o Python não tinha um equivalente, mas você poderia implementar o seu próprio.
Eu mesmo, gosto de simplificar (já vi alguns exemplos terrivelmente complexos na rede), algo assim ...
No Python 3.4 ( PEP 435 ), você pode tornar o Enum a classe base. Isso fornece um pouco de funcionalidade extra, descrita no PEP. Por exemplo, os membros enum são distintos dos números inteiros e são compostos de a
name
e avalue
.Se você não deseja digitar os valores, use o seguinte atalho:
Enum
implementações podem ser convertidas em listas e são iteráveis . A ordem de seus membros é a ordem de declaração e não tem nada a ver com seus valores. Por exemplo:fonte
object()
.Aqui está uma implementação:
Aqui está o seu uso:
fonte
__setattr__(self, name, value)
e, talvez,__delattr__(self, name)
para que, se você escrever acidentalmenteAnimals.DOG = CAT
, ele não seja silenciosamente bem-sucedido.Animals.DOG
; Além disso, os valores das constantes são seqüências de caracteres, de modo que as comparações com essas constantes são mais lentas do que se, digamos, números inteiros fossem permitidos como valores.setattr()
função dentro do__init__()
método em vez do__getattr__()
método de overidding . Eu suponho que isso deve funcionar da mesma maneira: classe Enum (objeto): def __init __ (self, enum_string_list): if type (enum_string_list) == list: for enum_string in enum_string_list: setattr (self, enum_string, enum_string) else: raise AttributeErrortry-except
bloco?Se você precisar dos valores numéricos, eis a maneira mais rápida:
No Python 3.x, você também pode adicionar um espaço reservado com estrela no final, que absorverá todos os valores restantes do intervalo, caso você não se importe em desperdiçar memória e não possa contar:
fonte
A melhor solução para você depende do que você precisa do seu falso
enum
.Enum simples:
Se você precisar da
enum
lista apenas de nomes que identificam itens diferentes , a solução de Mark Harrison (acima) é ótima:O uso de um
range
também permite definir qualquer valor inicial :Além do acima, se você também exigir que os itens pertençam a um contêiner de algum tipo, incorpore-os em uma classe:
Para usar o item enum, agora você precisa usar o nome do contêiner e o nome do item:
Enum complexo:
Para longas listas de enum ou usos mais complicados de enum, essas soluções não serão suficientes. Você pode consultar a receita de Will Ware para Simulação de enumerações em Python, publicada no Python Cookbook . Uma versão online disso está disponível aqui .
Mais informações:
PEP 354: Enumerações em Python tem os detalhes interessantes de uma proposta de enum em Python e por que ela foi rejeitada.
fonte
range
você pode omitir o primeiro argumento se for 0my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Em seguida,my_enum
pode ser usado na pesquisa, por exemplo,my_enum['Item0']
pode ser um índice em uma sequência. Você pode agrupar o resultado destr.split
uma função que lança uma exceção se houver duplicatas.Flag1, Flag2, Flag3 = [2**i for i in range(3)]
O padrão de enumeração typesafe usado no Java pré-JDK 5 possui várias vantagens. Assim como na resposta de Alexandru, você cria uma classe e os campos no nível de classe são os valores enum; no entanto, os valores enum são instâncias da classe e não números inteiros pequenos. Isso tem a vantagem de que seus valores de enum não se comparam inadvertidamente com números inteiros pequenos, você pode controlar como eles são impressos, adicionar métodos arbitrários, se isso for útil, e fazer afirmações usando isinstance:
Um tópico recente no python-dev apontou que existem algumas bibliotecas enum em estado selvagem, incluindo:
fonte
Uma classe Enum pode ser uma linha.
Como usá-lo (pesquisa direta e reversa, chaves, valores, itens etc.)
fonte
in
palavra-chave para procurar membros que sejam legais. Exemplo de uso:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Então eu concordo. Não vamos impor segurança de tipo em Python, mas gostaria de me proteger de erros tolos. Então, o que pensamos sobre isso?
Isso me impede de colisão de valores ao definir meus enums.
Há outra vantagem útil: pesquisas reversas muito rápidas:
fonte
Animal = Enum('horse', 'dog', 'cat')
. Também pego o ValueError em getattr no caso de um item ausente em self.values - parece melhor gerar um AttributeError com a string de nome fornecida. Não consegui que a metaclasse funcionasse no Python 2.7 com base no meu conhecimento limitado nessa área, mas minha classe Enum personalizada funciona bem com métodos de instância direta.O Python não possui um equivalente interno
enum
e outras respostas têm idéias para implementar o seu próprio (você também pode estar interessado na versão superior do livro de receitas do Python).No entanto, em situações em que um
enum
seria chamado em C, normalmente acabo usando apenas seqüências de caracteres simples : devido à maneira como os objetos / atributos são implementados, (C) o Python é otimizado para trabalhar de maneira muito rápida com sequências curtas, portanto, não realmente não há nenhum benefício em desempenho ao usar números inteiros. Para se proteger contra erros de digitação / valores inválidos, você pode inserir cheques nos locais selecionados.(Uma desvantagem em comparação ao uso de uma classe é que você perde o benefício do preenchimento automático)
fonte
Em 10/05/2013, Guido concordou em aceitar o PEP 435 na biblioteca padrão do Python 3.4. Isso significa que o Python finalmente tem suporte embutido 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á no Pypi como enum34 .
Declaração:
Representação:
Iteração:
Acesso programático:
Para mais informações, consulte a proposta . A documentação oficial provavelmente seguirá em breve.
fonte
Prefiro definir enums em Python da seguinte forma:
É mais à prova de erros do que usar números inteiros, já que você não precisa se preocupar em garantir que os números inteiros sejam únicos (por exemplo, se você disse que Dog = 1 e Cat = 1 você seria ferrado).
É mais à prova de erros do que usar strings, pois você não precisa se preocupar com erros de digitação (por exemplo, x == "catt" falha silenciosamente, mas x == Animal.Catt é uma exceção de tempo de execução).
fonte
Use-o assim:
se você deseja apenas símbolos únicos e não se importa com os valores, substitua esta linha:
com isso:
fonte
enum(names)
paraenum(*names)
- então você pode soltar o parêntese extra ao chamá-lo.No Python 3.4, haverá suporte oficial para enums. Você pode encontrar documentação e exemplos aqui na página de documentação do Python 3.4 .
fonte
Hmmm ... Suponho que a coisa mais próxima de um enum seria um dicionário, definido assim:
ou
Em seguida, você pode usar o nome simbólico para as constantes assim:
Existem outras opções, como uma lista de tuplas ou uma tupla, mas o dicionário é o único que fornece uma maneira "simbólica" (cadeia constante) de acessar o valor.
Edit: Eu também gosto da resposta de Alexandru!
fonte
Outra implementação muito simples de uma enumeração em Python, usando
namedtuple
:ou alternativamente,
Como o método acima dessas subclasses
set
, isso permite:Mas tem mais flexibilidade, pois pode ter chaves e valores diferentes. Isso permite
para agir como esperado, se você usar a versão que preenche os valores numéricos seqüenciais.
fonte
O que eu uso:
Como usar:
Portanto, isso fornece constantes inteiras como state.PUBLISHED e as duas tuplas para serem usadas como opções nos modelos do Django.
fonte
A davidg recomenda o uso de dictos. Eu daria um passo adiante e usaria conjuntos:
Agora você pode testar se um valor corresponde a um dos valores do conjunto como este:
como o dF, no entanto, eu normalmente apenas uso constantes em vez de enumerações.
fonte
Mantenha simples:
Então:
fonte
Este é o melhor que eu já vi: "Enums de primeira classe em Python"
http://code.activestate.com/recipes/413486/
Dá a você uma classe, e a classe contém todas as enumerações. As enums podem ser comparadas entre si, mas não têm nenhum valor específico; você não pode usá-los como um valor inteiro. (Resisti a isso no começo porque estou acostumado a enumerações C, que são valores inteiros. Mas se você não pode usá-lo como um número inteiro, não pode usá-lo como um número inteiro por engano, então, no geral, acho que é uma vitória .) Cada enumeração é um valor único. Você pode imprimir enumerações, iterar sobre elas, testar se um valor de enumeração está "na" enumeração. É bem completo e liso.
Editar (cfi): o link acima não é compatível com Python 3. Aqui está o meu porto de enum.py para o Python 3:
fonte
.__int__()
método deve gerar uma exceção para uma enumeração; mas deve haver uma maneira de obter o valor. E deve ser possível definir valores inteiros específicos no momento da definição da classe, para que você possa usar uma enumeração para coisas como as constantes nostat
módulo.Eu tive ocasião de precisar de uma classe Enum, com o objetivo de decodificar um formato de arquivo binário. Os recursos que eu queria era a definição concisa de enum, a capacidade de criar livremente instâncias do enum por valor inteiro ou string e uma apresentação útil
repr
. Aqui está o que eu acabei com:Um exemplo caprichoso de usá-lo:
Características principais:
str()
,int()
erepr()
todos produzem a saída mais útil possível, respectivamente o nome da enumartion, seu valor inteiro e uma expressão Python que é avaliada novamente na enumeração.is
fonte
__instancecheck__
método. Classes não são coleções de instâncias, por isso1 in Fruit
é um absurdo. No entanto, a versão vinculada suporta oisinstance(1, Fruit)
que seria mais correto em termos de noção de classes e instâncias.O novo padrão no Python é o PEP 435 , portanto, uma classe Enum estará disponível em versões futuras do Python:
No entanto, para começar a usá-lo agora, você pode instalar a biblioteca original que motivou o PEP:
Em seguida, você pode usá-lo conforme seu guia on-line :
fonte
Se você nomear, o problema é seu, mas se não criar objetos em vez de valores, você poderá fazer isso:
Ao usar outras implementações localizadas aqui (também ao usar instâncias nomeadas no meu exemplo), você deve ter certeza de que nunca tenta comparar objetos de diferentes enumerações. Pois aqui está uma possível armadilha:
Caramba!
fonte
Eu realmente gosto da solução de Alec Thomas (http://stackoverflow.com/a/1695250):
Sua aparência é elegante e limpa, mas é apenas uma função que cria uma classe com os atributos especificados.
Com uma pequena modificação na função, podemos fazê-la agir um pouco mais 'enumy':
Isso cria uma enumeração baseada em um tipo especificado. Além de fornecer acesso a atributos como a função anterior, ele se comporta como seria de esperar de um Enum em relação aos tipos. Também herda a classe base.
Por exemplo, enumerações inteiras:
Outra coisa interessante que pode ser feita com esse método é personalizar o comportamento específico, substituindo os métodos internos:
fonte
O pacote enum do PyPI fornece uma implementação robusta de enumerações. Uma resposta anterior mencionou PEP 354; isso foi rejeitado, mas a proposta foi implementada http://pypi.python.org/pypi/enum .
O uso é fácil e elegante:
fonte
A sugestão de Alexandru de usar constantes de classe para enumerações funciona muito bem.
Também gosto de adicionar um dicionário para cada conjunto de constantes para pesquisar uma representação de string legível por humanos.
Isso serve para dois propósitos: a) fornece uma maneira simples de imprimir bastante sua enumeração eb) o dicionário agrupa logicamente as constantes para que você possa testar a associação.
fonte
Aqui está uma abordagem com algumas características diferentes que considero valiosas:
e o mais importante evita comparações entre enumerações de tipos diferentes !
Baseado em http://code.activestate.com/recipes/413486-first-class-enums-in-python .
Muitos documentos incluídos aqui para ilustrar o que há de diferente nessa abordagem.
fonte
Aqui está uma variante da solução de Alec Thomas :
fonte
Esta solução é uma maneira simples de obter uma classe para a enumeração definida como uma lista (sem mais atribuições inteiras irritantes):
enumeration.py:
example.py:
fonte
type(class_name, (object,), dict(...))
lugar?Embora a proposta original de enum, PEP 354 , tenha sido rejeitada anos atrás, ela continua voltando. Algum tipo de enum deveria ser adicionado ao 3,2, mas foi adiado para 3,3 e depois esquecido. E agora há um PEP 435 destinado à inclusão no Python 3.4. A implementação de referência do 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 - desde que as pessoas possam concordar com o que esse "algo" deve ser. Essa é a parte mais difícil. Veja os tópicos iniciando aqui e aqui e meia dúzia de outros tópicos nos primeiros meses de 2013.
Enquanto isso, toda vez que isso acontece, uma série de novos designs e implementações aparecem no PyPI, ActiveState etc., portanto, se você não gosta do design do FLUFL, tente uma pesquisa no PyPI .
fonte
Use o seguinte.
Eu usei isso para as opções de modelo do Django , e parece muito pitônico. Não é realmente um Enum, mas faz o trabalho.
fonte