2016-12-31 26 views
23

Zastanawiam się, jaki jest poprawny sposób konwersji (deserializacji) łańcucha znaków na klasę Enum w Pythonie. Wydaje się, że wykonuje to zadanie, ale nie jestem pewien, czy jest wystarczająco bezpieczny.Konwertuj ciąg na Enum w języku Python

Wystarczy być bardziej szczegółowe, chciałbym przekonwertować 'debug' ciąg do obiektu Enum takich jak to:

class BuildType(Enum): 
    debug = 200 
    release = 400 

Odpowiedz

39

Ta funkcja jest już wbudowany w Enum [1]:

>>> from enum import Enum 
>>> class Build(Enum): 
... debug = 200 
... build = 400 
... 
>>> Build['debug'] 
<Build.debug: 200> 

[1] oficjalne dokumentów: Enum programmatic access

+0

Tak, tego właśnie szukałem. Link do oficjalnych dokumentów w tej sprawie byłby miły. – Vladius

+0

@Vladius: Dodano link. –

+0

Co z wartością rezerwową w przypadku, gdy dane wejściowe wymagają dezynfekcji? Coś w rodzaju 'Build.get ('nielegalnie', Build.debug)'? – Hetzroni

1
def custom_enum(typename, items_dict): 
    class_definition = """ 
from enum import Enum 

class {}(Enum): 
    {}""".format(typename, '\n '.join(['{} = {}'.format(k, v) for k, v in items_dict.items()])) 

    namespace = dict(__name__='enum_%s' % typename) 
    exec(class_definition, namespace) 
    result = namespace[typename] 
    result._source = class_definition 
    return result 

MyEnum = custom_enum('MyEnum', {'a': 123, 'b': 321}) 
print(MyEnum.a, MyEnum.b) 

Albo trzeba przekonwertować ciąg znanego Enum?

class MyEnum(Enum): 
    a = 'aaa' 
    b = 123 

print(MyEnum('aaa'), MyEnum(123)) 

A:

class BuildType(Enum): 
    debug = 200 
    release = 400 

print(BuildType.__dict__['debug']) 

print(eval('BuildType.debug')) 
print(type(eval('BuildType.debug')))  
print(eval(BuildType.__name__ + '.debug')) # for work with code refactoring 
+0

mam na myśli Chciałbym przekonwertować 'debug' ciąg do wyliczenia takiego: ' '' python klasy BuildType (Enum): debug = 200 wydanie = 400 '' ' – Vladius

+0

Świetne wskazówki! Czy użycie '__dict__' jest takie samo jak' getattr'? Martwię się o kolizje nazw z wewnętrznymi atrybutami Pythona ... – Vladius

+0

Oh ... tak to samo, co 'getattr'. Nie widzę powodu do kolizji nazw. Po prostu nie możesz ustawić słowa kluczowego jako pola klasy. – ADR

0

Inną alternatywą (zwłaszcza użyteczne, jeśli twoje struny nie odwzorowują 1-1 do twoich enum przypadków) to dodać staticmethod do Enum, np:

class QuestionType(enum.Enum): 
    MULTI_SELECT = "multi" 
    SINGLE_SELECT = "single" 

    @staticmethod 
    def from_str(label): 
     if label in ('single', 'singleSelect'): 
      return QuestionType.SINGLE_SELECT 
     elif label in ('multi', 'multiSelect'): 
      return QuestionType.MULTI_SELECT 
     else: 
      raise NotImplementedError 

Następnie można zrobić question_type = QuestionType.from_str('singleSelect')