Як перетворити 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'].
— Мартін Пітерс

Бінго, дуже приголомшливо! Я шукав сторінку для 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", але моя конкретна програма використовує текст безпосередньо.


Чому б просто не визначити __int__і __str__методи в екземплярі Enum?
— Тім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.