Como converter int para Enum em python?

99

Usando o novo recurso Enum (via backport enum34 ) com o python 2.7.6.

Dada a definição a seguir, como posso converter um int no valor Enum correspondente?

from enum import Enum

class Fruit(Enum):
    Apple = 4
    Orange = 5
    Pear = 6

Eu sei que posso criar manualmente uma série de declarações if para fazer a conversão, mas existe uma maneira fácil de fazer a conversão em python? Basicamente, eu gostaria de uma função ConvertIntToFruit (int) que retornasse um valor enum.

Meu caso de uso é eu tenho um arquivo csv de registros onde estou lendo cada registro em um objeto. Um dos campos do arquivo é um campo inteiro que representa uma enumeração. Enquanto estou preenchendo o objeto, gostaria de converter esse campo inteiro do arquivo no valor Enum correspondente no objeto.

Do utilizador
fonte

Respostas:

168

Você 'chama' a Enumclasse:

Fruit(5)

para se transformar 5em Fruit.Orange:

>>> from enum import Enum
>>> class Fruit(Enum):
...     Apple = 4
...     Orange = 5
...     Pear = 6
... 
>>> Fruit(5)
<Fruit.Orange: 5>

Na seção Acesso programático aos membros da enumeração e seus atributos da documentação:

Às vezes, é útil acessar membros em enumerações programaticamente (ou seja, situações em Color.redque não é possível porque a cor exata não é conhecida no momento da escrita do programa). Enumpermite esse acesso:

>>> Color(1)
<Color.red: 1>
>>> Color(3)
<Color.blue: 3>

Em uma nota relacionada: para mapear um valor de string contendo o nome de um membro enum, use inscrição:

>>> s = 'Apple'
>>> Fruit[s]
<Fruit.Apple: 4>
Martijn Pieters
fonte
Obrigado acabou de receber isso enquanto eu estava relendo a documentação. Não ficou claro para mim na minha primeira leitura. Também tentei usar uma string e é bom ver que funciona quando o valor de enumeração também é uma string e estou assumindo qualquer valor de objeto arbitrário.
Usuário
Muito bom, então a conversão é por valor. Existe uma analogia para por nome que não seja através de uma compreensão de lista para filtrar a lista enum e obter a correspondência nos atributos de nome?
jxramos
4
@jxramos siga o link de documentação em minha resposta, ele está explicitamente coberto lá. Use o acesso artigo: Fruit['Orange'].
Martijn Pieters
Bingo, muito legal! Eu procurei a página para convert, coercee castmas não bater em nada. Parece que a magia foi access enum members by name, use item access. Perfecto, muito obrigado, vou limpar meu código com essa sintaxe.
jxramos
Ainda mais legal é que posso usar coisas como "foobar" in Fruit.__members__testar a associação e até mesmo conseguir Fruit.get( 'foobar', Fruit.Orange )obter o sabor padrão do Enum. Meu código está parecendo muito mais simplificado removendo todos esses scaffolds de pesquisa de acessórios que estabeleci anteriormente.
jxramos
1

Acho que em palavras simples é converter o intvalor em Enumchamando EnumType(int_value), depois disso acesse o namedo Enumobjeto:

my_fruit_from_int = Fruit(5) #convert to int
fruit_name = my_fruit_from_int.name #get the name
print(fruit_name) #Orange will be printed here

Ou como uma função:

def convert_int_to_fruit(int_value):
    try:
        my_fruit_from_int = Fruit(int_value)
        return my_fruit_from_int.name
    except:
        return None
Ali Ezzat Odeh
fonte
-1

Eu queria algo semelhante para que pudesse acessar qualquer parte do par de valores de uma única referência. A versão vanilla:

#!/usr/bin/env python3


from enum import IntEnum


class EnumDemo(IntEnum):
    ENUM_ZERO       = 0
    ENUM_ONE        = 1
    ENUM_TWO        = 2
    ENUM_THREE      = 3
    ENUM_INVALID    = 4


#endclass.


print('Passes')
print('1) %d'%(EnumDemo['ENUM_TWO']))
print('2) %s'%(EnumDemo['ENUM_TWO']))
print('3) %s'%(EnumDemo.ENUM_TWO.name))
print('4) %d'%(EnumDemo.ENUM_TWO))
print()


print('Fails')
print('1) %d'%(EnumDemo.ENUM_TWOa))

A falha lança uma exceção como seria de se esperar.

Uma versão mais robusta:

#!/usr/bin/env python3


class EnumDemo():


    enumeration =   (
                        'ENUM_ZERO',    # 0.
                        'ENUM_ONE',     # 1.
                        'ENUM_TWO',     # 2.
                        'ENUM_THREE',   # 3.
                        'ENUM_INVALID'  # 4.
                    )


    def name(self, val):
        try:

            name = self.enumeration[val]
        except IndexError:

            # Always return last tuple.
            name = self.enumeration[len(self.enumeration) - 1]

        return name


    def number(self, val):
        try:

            index = self.enumeration.index(val)
        except (TypeError, ValueError):

            # Always return last tuple.
            index = (len(self.enumeration) - 1)

        return index


#endclass.


print('Passes')
print('1) %d'%(EnumDemo().number('ENUM_TWO')))
print('2) %s'%(EnumDemo().number('ENUM_TWO')))
print('3) %s'%(EnumDemo().name(1)))
print('4) %s'%(EnumDemo().enumeration[1]))
print()
print('Fails')
print('1) %d'%(EnumDemo().number('ENUM_THREEa')))
print('2) %s'%(EnumDemo().number('ENUM_THREEa')))
print('3) %s'%(EnumDemo().name(11)))
print('4) %s'%(EnumDemo().enumeration[-1]))

Quando não usado corretamente, evita a criação de uma exceção e, em vez disso, retorna uma indicação de falha. Uma maneira mais pitônica de fazer isso seria retornar "Nenhum", mas meu aplicativo em particular usa o texto diretamente.

user3355323
fonte
Por que não apenas definir os métodos __int__e __str__em uma instância Enum?
Tim