Как преобразовать int в Enum в Python?

96

Использование новой функции Enum (через backport enum34 ) с python 2.7.6.

Учитывая следующее определение, как я могу преобразовать int в соответствующее значение Enum?

from enum import Enum

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

Я знаю, что могу вручную создать серию операторов if для преобразования, но есть ли простой питонический способ преобразования? В принципе, мне нужна функция ConvertIntToFruit (int), которая возвращает значение перечисления.

Мой вариант использования - у меня есть файл csv записей, в котором я читаю каждую запись в объект. Одно из полей файла - это целочисленное поле, которое представляет собой перечисление. Когда я заполняю объект, я хотел бы преобразовать это целочисленное поле из файла в соответствующее значение Enum в объекте.

Пользователь
источник

Ответы:

165

Вы «называете» Enumкласс:

Fruit(5)

превратиться 5в Fruit.Orange:

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

В разделе документации Программный доступ к членам перечисления и их атрибутам :

Иногда Color.redбывает полезно получить доступ к членам в перечислениях программно (т. Е. В ситуациях, когда этого не произойдет, потому что точный цвет неизвестен во время написания программы). Enumпозволяет такой доступ:

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

В соответствующем примечании: чтобы отобразить строковое значение, содержащее имя члена перечисления, используйте подписку:

>>> s = 'Apple'
>>> Fruit[s]
<Fruit.Apple: 4>
Мартейн Питерс
источник
Спасибо, только что получил это, поскольку я перечитывал документацию. Мне было непонятно при первом просмотре. Также я просто попытался использовать строку и приятно видеть, что она работает, когда значение перечисления также является строкой, и я предполагаю любое произвольное значение объекта.
Пользователь
Очень хорошо, поэтому конверсия производится по стоимости. Есть ли аналог для по имени, отличный от понимания списка, для фильтрации по списку перечислений и поиска совпадений по атрибутам имени?
jxramos
4
@jxramos действительно следуйте ссылке на документацию в моем ответе, она явно там освещена. Используйте доступ пункт: Fruit['Orange'].
Martijn Pieters
Бинго, очень круто! Я искал страницу для convert, coerceи , castно ничего не достиг. Похоже, волшебство было access enum members by name, use item access. Perfecto, большое спасибо, собираюсь очистить мой код с помощью этого синтаксиса.
jxramos
Еще круче то, что я могу использовать такие вещи, как "foobar" in Fruit.__members__тестирование на членство, и даже снимать, Fruit.get( 'foobar', Fruit.Orange )чтобы получить тот вариант Enum по умолчанию. Мой код выглядит намного более упрощенным, удаляя все эти вспомогательные строительные леса, которые я заложил ранее.
jxramos
1

Я думаю, что простыми словами это преобразовать intзначение в Enumвызов EnumType(int_value), после чего получить доступ nameк Enumобъекту:

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

Или как функция:

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

Мне нужно было что-то подобное, чтобы я мог получить доступ к любой части пары значений по одной ссылке. Ванильная версия:

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

Сбой вызывает исключение, как и следовало ожидать.

Более надежная версия:

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

При неправильном использовании это позволяет избежать создания исключения и вместо этого возвращает индикацию сбоя. Более питонический способ сделать это - вернуть «None», но мое конкретное приложение использует текст напрямую.

user3355323
источник
Почему бы просто не определить методы __int__и __str__в экземпляре Enum?
Тим