Jak uzyskać wszystkie wartości z klasy wyliczeniowej Pythona?

155

Używam biblioteki Enum4 do tworzenia klasy wyliczeniowej w następujący sposób:

class Color(Enum):
    RED = 1
    BLUE = 2

Chcę [1, 2]gdzieś wydrukować jako listę. Jak mogę to osiągnąć?

user1159517
źródło

Odpowiedzi:

57

Możesz użyć IntEnum :

from enum import IntEnum

class Color(IntEnum):
   RED = 1
   BLUE = 2


print(int(Color.RED))   # prints 1

Aby uzyskać listę int:

enum_list = list(map(int, Color))
print(enum_list) # prints [1, 2]
Marcin
źródło
Używasz strony trzeciej. Ale jest też napisane, że ma intenum
Marcin
Jak drukować jak [(1, „CZERWONY”), (2, „NIEBIESKI”)]
user1159517
A co z tym: a = [(int(v), str(v)) for v in Color]a potem print(a).
Marcin
42
Co powiesz na to:[(color.value, color.name) for color in Color]
vlad-ardelean
2
Komentarz @ vlad-ardelean jest najlepszy i najbardziej pytoniczny. To idiomatyczne użycie typu Enum, eleganckie i wyjątkowo czytelne
dusktreader
479

Możesz wykonać następujące czynności:

[e.value for e in Color]
ozgur
źródło
1
@ user2340939 To zwraca listę wyliczeń, a nie listę wartości. Jeśli nie masz nic przeciwko, równie dobrze możesz użyćlist(Color)
endolith
26

Aby użyć Enum z dowolnym typem wartości, spróbuj tego:
Zaktualizowany o kilka ulepszeń ... Dzięki @Jeff, twoja wskazówka!

from enum import Enum

class Color(Enum):
    RED = 1
    GREEN = 'GREEN'
    BLUE = ('blue', '#0000ff')

    @staticmethod
    def list():
        return list(map(lambda c: c.value, Color))

print(Color.list())

W wyniku:

[1, 'GREEN', ('blue', '#0000ff')]
Jeff
źródło
6
Użyłbym @classmethod zamiast @ staticmethod
ISONecroMAn
1
@ISONecroMAn Myślę, @classmethodże wymagałoby to stworzenia instancji Colorklasy. Dlatego staticmethodwydaje się, że jest to właściwy wybór.
Leonid Dashko
1
@LeonidDashko wcale nie. Zobacz moją odpowiedź.
blueFast
@LeonidDashko @dangoonfast jest poprawne. Możesz użyć @classmethodi użyć return list(map(lambda c: c.value, cls))zamiast tego.
Riptyde4
Próbując poprawić szybkość tego, są dwie uwagi: użycie Color.__members__.values()zamiast Koloru w map()rozmowie da od razu 30% doładowanie. Możesz wtedy uzyskać nieco większą prędkość, zastępując lambdę przez operator.attrgetter('value').
Giacomo Lacava
21

Na podstawie odpowiedzi @Jeff, refaktoryzowano, aby użyć a classmethod, aby można było ponownie użyć tego samego kodu dla dowolnego ze swoich wyliczeń:

from enum import Enum

class ExtendedEnum(Enum):

    @classmethod
    def list(cls):
        return list(map(lambda c: c.value, cls))

class OperationType(ExtendedEnum):
    CREATE = 'CREATE'
    STATUS = 'STATUS'
    EXPAND = 'EXPAND'
    DELETE = 'DELETE'

print(OperationType.list())

Produkuje:

['CREATE', 'STATUS', 'EXPAND', 'DELETE']
blueFast
źródło
9

class enum.Enumto klasa, która rozwiązuje wszystkie Twoje potrzeby związane z wyliczaniem, więc musisz po prostu dziedziczyć po niej i dodać własne pola. Od tego momentu wszystko, co musisz zrobić, to po prostu wywołać jego atrybuty: name& value:

from enum import Enum

class Letter(Enum):
   A = 1
   B = 2
   C = 3

print({i.name: i.value for i in Letter})
# prints {'A': 1, 'B': 2, 'C': 3}
Meysam
źródło
6

Więc Enumma __members__dyktando. Rozwiązanie zaproponowane przez @ozgur jest naprawdę najlepsze, ale możesz to zrobić, co robi to samo, przy większej ilości pracy

[color.value for color_name, color in Color.__members__.items()]

__members__Słownik mógłby się przydać, jeśli chcesz wstawić rzeczy dynamicznie w nim ... w jakiejś szalonej sytuacji.

[EDYCJA] Najwyraźniej __members__nie jest słownikiem, ale mapą proxy. Co oznacza, że ​​nie możesz łatwo dodawać do niego elementów.

Możesz jednak robić dziwne rzeczy, takie jak MyEnum.__dict__['_member_map_']['new_key'] = 'new_value', a potem możesz użyć nowego klucza, takiego jak MyEnum.new_key.... ale to tylko szczegół implementacji i nie powinno się nim bawić. Za czarną magię płacą ogromne koszty utrzymania.

vlad-ardelean
źródło
Tylko pasek boczny: czy można dodawać elementy __members__? Byłby to interesujący sposób na zezwolenie na rozszerzenia, tworząc w ten sposób nowych Enumczłonków. ... przy okazji, głosowano za wprowadzeniem nowego ( dla mnie ) atrybutu do tabeli.
IAbstract
@IAbstract: Nie, to jest niedozwolone. Jeśli ktoś znajdzie sposób na dodawanie / odejmowanie członków po utworzeniu Enum, prawdopodobnie złamie to Enum.
Ethan Furman,
@IAbstract: Dodawanie nowych członków po fakcie zwykle nie jest dobrym pomysłem. Jeśli naprawdę chcesz, sprawdź tę odpowiedź .
Ethan Furman
2

Użyj, _member_names_aby szybko uzyskać łatwy wynik, jeśli są to tylko nazwy, tj

Color._member_names_

Masz również, _member_map_który zwraca uporządkowany słownik elementów. Funkcja ta zwraca collections.OrderedDict, więc trzeba Color._member_names_.items()i Color._member_names_.values()do zabawy. Na przykład

return list(map(lambda x: x.value, Color._member_map_.values()))

zwróci wszystkie prawidłowe wartości Color

EliuX
źródło
2

Korzystanie classmethodz __members__:

class RoleNames(str, Enum):
    AGENT = "agent"
    USER = "user"
    PRIMARY_USER = "primary_user"
    SUPER_USER = "super_user"
    
    @classmethod
    def list_roles(cls):
        role_names = [member.value for role, member in cls.__members__.items()]
        return role_names
role_names = RoleNames.list_roles()
print(role_names)

lub jeśli masz wiele klas Enum i chcesz wyodrębnić metodę klasy:

class BaseEnum(Enum):
    @classmethod
    def list_roles(cls):
        role_names = [member.value for role, member in cls.__members__.items()]
        return role_names


class RoleNames(str, BaseEnum):    
    AGENT = "agent"
    USER = "user"
    PRIMARY_USER = "primary_user"
    SUPER_USER = "super_user"
    

class PermissionNames(str, BaseEnum):
    READ = "updated_at"
    WRITE = "sort_by"
    READ_WRITE = "sort_order"

bwl1289
źródło