¿Cómo convertir int a Enum en Python?


96

Usando la nueva función Enum (a través de backport enum34 ) con python 2.7.6.

Dada la siguiente definición, ¿cómo puedo convertir un int al valor de Enum correspondiente?

from enum import Enum

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

Sé que puedo crear a mano una serie de declaraciones if para realizar la conversión, pero ¿hay una forma pitónica fácil de convertir? Básicamente, me gustaría una función ConvertIntToFruit (int) que devuelva un valor de enumeración.

Mi caso de uso es que tengo un archivo csv de registros donde leo cada registro en un objeto. Uno de los campos del archivo es un campo entero que representa una enumeración. Mientras estoy rellenando el objeto, me gustaría convertir ese campo entero del archivo en el valor Enum correspondiente en el objeto.

Respuestas:


165

Tú 'llamas' a la Enumclase:

Fruit(5)

convertirse 5en Fruit.Orange:

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

Desde la sección Acceso programático a los miembros de la enumeración y sus atributos de la documentación:

A veces es útil acceder a los miembros en enumeraciones mediante programación (es decir, situaciones en las Color.redque no es posible porque no se conoce el color exacto en el momento de escribir el programa). Enumpermite tal acceso:

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

En una nota relacionada: para asignar un valor de cadena que contenga el nombre de un miembro de enumeración, use la suscripción:

>>> s = 'Apple'
>>> Fruit[s]
<Fruit.Apple: 4>

Gracias, acabo de recibir esto mientras volvía a leer la documentación. No me quedó claro en mi primer vistazo. También intenté usar una cadena y es bueno ver que funciona cuando el valor de enumeración también es una cadena y estoy asumiendo cualquier valor de objeto arbitrario.
Usuario

Muy bien, la conversión es por valor. ¿Existe un análogo para por nombre que no sea a través de una lista de comprensión para filtrar a través de la lista de enumeración y hacer coincidir los atributos del nombre?
jxramos

4
@jxramos sigue el enlace de documentación en mi respuesta, se cubre explícitamente allí. Utilizar el acceso material: Fruit['Orange'].
Martijn Pieters

¡Bingo, muy asombroso! He buscado en la página para convert, coercey castaunque no toque nada. Parece que la magia fue access enum members by name, use item access. Perfecto, muchas gracias, voy a limpiar mi código con esta sintaxis.
jxramos

Aún más genial es que puedo usar cosas como "foobar" in Fruit.__members__para probar la membresía e incluso lograrlo Fruit.get( 'foobar', Fruit.Orange )para obtener ese sabor Enum predeterminado. Mi código se ve mucho más simplificado al eliminar todos estos andamios de búsqueda de accesorios que establecí anteriormente.
jxramos

1

Creo que en palabras simples es convertir el intvalor en Enumllamando EnumType(int_value), luego acceda al namedel 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

O en función:

def convert_int_to_fruit(int_value):
    try:
        my_fruit_from_int = Fruit(int_value)
        return my_fruit_from_int.name
    except:
        return None

-1

Quería algo similar para poder acceder a cualquier parte del par de valores desde una única referencia. La versión vainilla:

#!/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))

La falla lanza una excepción como se esperaría.

Una versión más 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]))

Cuando no se usa correctamente, esto evita crear una excepción y, en cambio, devuelve una indicación de falla. Una forma más Pythonic de hacer esto sería devolver "Ninguno" pero mi aplicación particular usa el texto directamente.


¿Por qué no definir los métodos __int__y __str__en una instancia de Enum?
Tim
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.