Як перетворити 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.