user1159517
user1159517

Reputation: 6350

How to get all values from python enum class?

I'm using Enum4 library to create an enum class as follows:

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

I want to print [1, 2] as a list somewhere. How can I achieve this?

Upvotes: 474

Views: 452716

Answers (18)

lexxai
lexxai

Reputation: 85

Improved @supermodo method with lru caching of results.

from enum import Enum, StrEnum
from functools import lru_cache

class LruCachedEnum(Enum):
    @classmethod
    @lru_cache(maxsize=1)
    def to_dict(cls):
        print("##### singleton of to_dict")
        return {e.name: e.value for e in cls}

    @classmethod
    @lru_cache(maxsize=1)
    def items(cls):
        print("##### singleton of items")
        return [(e.name, e.value) for e in cls]

    @classmethod
    @lru_cache(maxsize=1)
    def keys(cls):
        print("##### singleton of keys")
        return [e.name for e in cls]

    @classmethod
    @lru_cache(maxsize=1)
    def values(cls):
        print("##### singleton of values")
        return [e.value for e in cls]


class MODES(StrEnum, LruCachedEnum):
    ORIGINAL = "original"
    REDUCED = "reduced"
    NORMALIZED = "normalized"
    CROPPED = "cropped"
    CROPPED_REDUCED = "cropped_reduced"


if __name__ == "__main__":
    print(type(MODES.ORIGINAL))  # Should be <enum 'MODES'>
    print(MODES.ORIGINAL.value, MODES.ORIGINAL == "original")
    print("\n# methods")
    print(MODES.to_dict())
    print(MODES.items())
    print(MODES.keys())
    print(MODES.values())
    print("\n# next loop by use cache")
    print(MODES.to_dict())
    print(MODES.items())
    print(MODES.keys())
    print(MODES.values())
    print("\n# is member:")
    for v in ["original", "small", "cropped"]:
        print(f"{v} is MEMBER of MODES: {v in MODES.values()}")

Result:

<enum 'MODES'>
original True

# methods
##### singleton of to_dict
{'ORIGINAL': 'original', 'REDUCED': 'reduced', 'NORMALIZED': 'normalized', 'CROPPED': 'cropped', 'CROPPED_REDUCED': 'cropped_reduced'}
##### singleton of items
[('ORIGINAL', 'original'), ('REDUCED', 'reduced'), ('NORMALIZED', 'normalized'), ('CROPPED', 'cropped'), ('CROPPED_REDUCED', 'cropped_reduced')]
##### singleton of keys
['ORIGINAL', 'REDUCED', 'NORMALIZED', 'CROPPED', 'CROPPED_REDUCED']
##### singleton of values
['original', 'reduced', 'normalized', 'cropped', 'cropped_reduced']

# next loop by use cache
{'ORIGINAL': 'original', 'REDUCED': 'reduced', 'NORMALIZED': 'normalized', 'CROPPED': 'cropped', 'CROPPED_REDUCED': 'cropped_reduced'}
[('ORIGINAL', 'original'), ('REDUCED', 'reduced'), ('NORMALIZED', 'normalized'), ('CROPPED', 'cropped'), ('CROPPED_REDUCED', 'cropped_reduced')]
['ORIGINAL', 'REDUCED', 'NORMALIZED', 'CROPPED', 'CROPPED_REDUCED']
['original', 'reduced', 'normalized', 'cropped', 'cropped_reduced']

# is member:
original is MEMBER of MODES: True
small is MEMBER of MODES: False
cropped is MEMBER of MODES: True

gist source code (Tested in Python 3.13.0)

Upvotes: 0

Peterino
Peterino

Reputation: 16777

An alternative form of the SuperEnum suggested by @supermodo, which allows iterating over the key-value pairs, and has less magic:

class SuperEnum(IntEnum):

    @classmethod
    def to_dict(cls):
        return {e.name: e.value for e in cls}

    @classmethod
    def items(cls):
        return [(e.name, e.value) for e in cls]

    @classmethod
    def keys(cls):
        return [e.name for e in cls]

    @classmethod
    def values(cls):
        return [e.value for e in cls]

Used like this:

class Roles(SuperEnum):
    ADMIN = 1
    USER = 2
    GUEST = 3

Allows you to do:

Roles.keys()  # ['ADMIN', 'USER', 'GUEST']
Roles.values()  # [1, 2, 3]
Roles.to_dict()  # {'ADMIN': 1, 'USER': 2, 'GUEST': 3}
for key, val in Roles.items():
    print(f"{key} > {val}")  # ADMIN -> 1, etc.

Generators (optimization)

Note that if you prefer generators over lists as return values for items(), keys() and values() then use round braces () instead of square brackets [], e.g.

    @classmethod
    def items(cls):
        return ((e.name, e.value) for e in cls)

    @classmethod
    def keys(cls):
        return (e.name for e in cls)

    @classmethod
    def values(cls):
        return (e.value for e in cls)

Generators are more memory-efficient and often preferred in the Python 3 standard library. The downside of them is that you need to convert them to lists to see the complete result (e.g. when working with them interactively), e.g.

Roles.items()  # <generator object SuperEnum.items.<locals>.<genexpr> at 0x7f3a8c787370>
list(Roles.items())  # [('ADMIN', 1), ('USER', 2), ('GUEST', 3)]
list(Roles.keys())  # ['ADMIN', 'USER', 'GUEST']
list(Roles.values())  # [1, 2, 3]

Upvotes: 4

blueFast
blueFast

Reputation: 44501

Based on the answer by @Jeff, refactored to use a classmethod so that you can reuse the same code for any of your enums:

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())

Produces:

['CREATE', 'STATUS', 'EXPAND', 'DELETE']

Upvotes: 174

Frank
Frank

Reputation: 351

if you are using StrEnum or IntEnum, just use the built-in star expression to unpack:

from enum import IntEnum
class Color(IntEnum):
    RED = 0
    GREEN = 1
colors = [*Color]

Upvotes: 25

NotSoShabby
NotSoShabby

Reputation: 3728

Im gonna throw another option into the mix.

If you don't want to refactor your current code with a different base class to all enums (like the inheritance answers in this thread), you can create a mixin class and just add it to the enums that need that functionality like so:

class ListValsMixIn:

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

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

print(Color.list())

Upvotes: 0

Omer Laufer
Omer Laufer

Reputation: 11

I believe an important comment on some of the answers above is to avoid naming a class method with the python builtin "list"

based on that: https://github.com/encode/django-rest-framework/issues/5884

Upvotes: 0

ldmtwo
ldmtwo

Reputation: 475

Here are some examples to easily convert Enum to a list/array of int, str, or Enum AND be able to sort.

import numpy as np

class Color(int,Enum):
    YELLOW = 3
    RED = 1
    BLUE = 2
    
print('1):',list(Color))
print('2):',np.array(list(Color))) ## int64 (8 bytes)
print('3):',sorted(np.array(Color, dtype=str)))
print('4):',np.array(sorted(Color), dtype=object))
print('5):',np.array(sorted(Color), dtype=np.int8)) # 1 byte
print('6):',np.array(sorted(Color, key=lambda x: -x.value), dtype=np.int8))
print('7):',np.array(sorted(Color, key=lambda x: str(x)), dtype=np.int8))

class Color(tuple,Enum):
    YELLOW = (3,3)
    RED = (1,1)
    BLUE = (2,2)
    
print('8):',np.array(sorted(Color)))
print('9):',list(map(tuple,sorted(Color, key=lambda x: -x[1]))))

Output:

1): [<Color.YELLOW: 3>, <Color.RED: 1>, <Color.BLUE: 2>]
2): [3 1 2]
3): ['Color.BLUE', 'Color.RED', 'Color.YELLOW']
4): [<Color.RED: 1> <Color.BLUE: 2> <Color.YELLOW: 3>]
5): [1 2 3]
6): [3 2 1]
7): [2 1 3]
8): [[1 1]
 [2 2]
 [3 3]]
9): [(3, 3), (2, 2), (1, 1)]

Upvotes: 2

supermodo
supermodo

Reputation: 813

You can have a SuperEnum like:

from enum import Enum

class SuperEnum(Enum):    
    @classmethod
    def to_dict(cls):
        """Returns a dictionary representation of the enum."""
        return {e.name: e.value for e in cls}
    
    @classmethod
    def keys(cls):
        """Returns a list of all the enum keys."""
        return cls._member_names_
    
    @classmethod
    def values(cls):
        """Returns a list of all the enum values."""
        return list(cls._value2member_map_.keys())

and use it like:

class Roles(SuperEnum):
    ADMIN = 1
    USER = 2
    GUEST = 3

so you can:

Roles.to_dict() # {'ADMIN': 1, 'USER': 2, 'GUEST': 3}
Roles.keys() # ['ADMIN', 'USER', 'GUEST']
Roles.values() # [1, 2, 3]

Upvotes: 21

Abhishek Jangalwa
Abhishek Jangalwa

Reputation: 441

Just use:

[e.value for e in Color]

Produces:

[1, 2]

And to get the names, use:

[e.name for e in Color]

Produces:

['RED', 'BLUE']

Upvotes: 38

EliuX
EliuX

Reputation: 12685

Use _member_names_ for a quick easy result if it is just the names, i.e.

Color._member_names_

Also, you have _member_map_ which returns an ordered dictionary of the elements. This function returns a collections.OrderedDict, so you have Color._member_map_.items() and Color._member_map_.values() to play with. E.g.

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

will return all the valid values of Color

Upvotes: 138

Bennie van Eeden
Bennie van Eeden

Reputation: 428

One way is to get the keys of the _value2member_map_ property:

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

list(Color._value2member_map_.keys())
# [1, 2]

Upvotes: 9

derwiwie
derwiwie

Reputation: 905

Given an enum based on the standard python3 Enum/IntEnum classes:

from enum import IntEnum

class LogLevel(IntEnum):
    DEBUG = 0
    INFO = 1
    WARNING = 2
    ERROR = 3

one can do the following to get a list of enum constants:

>>> print(list(LogLevel))
[<LogLevel.DEBUG: 0>, <LogLevel.INFO: 1>, <LogLevel.WARNING: 2>, <LogLevel.ERROR: 3>]

I find it more expressive to work on enum constants instead of ints. If the enum is inheriting from IntEnum, all enum constants are also ints and can used as such everywhere:

>>> level = LogLevel.DEBUG

>>> level == 0
True

>>> level == 1
False

>>> level == LogLevel.INFO
False

>>> level == LogLevel.DEBUG
True

>>> "%d" % level
'0'

>>> "%s" % level
'LogLevel.DEBUG'

Upvotes: 7

bwl1289
bwl1289

Reputation: 2078

Using a classmethod with __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)

or if you have multiple Enum classes and want to abstract the classmethod:

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"

Upvotes: 13

Meysam
Meysam

Reputation: 738

class enum.Enum is a class that solves all your enumeration needs, so you just need to inherit from it, and add your own fields. Then from then on, all you need to do is to just call it's attributes: 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}

Upvotes: 25

Jeff
Jeff

Reputation: 589

To use Enum with any type of value, try this:
Updated with some improvements... Thanks @Jeff, by your tip!

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())

As result:

[1, 'GREEN', ('blue', '#0000ff')]

Upvotes: 45

vlad-ardelean
vlad-ardelean

Reputation: 7622

So the Enum has a __members__ dict. The solution that @ozgur proposed is really the best, but you can do this, which does the same thing, with more work

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

The __members__ dictionary could come in handy if you wanted to insert stuff dynamically in it... in some crazy situation.

[EDIT] Apparently __members__ is not a dictionary, but a map proxy. Which means you can't easily add items to it.

You can however do weird stuff like MyEnum.__dict__['_member_map_']['new_key'] = 'new_value', and then you can use the new key like MyEnum.new_key.... but this is just an implementation detail, and should not be played with. Black magic is payed for with huge maintenance costs.

Upvotes: 10

Ozgur Vatansever
Ozgur Vatansever

Reputation: 52213

You can do the following:

[e.value for e in Color]

Upvotes: 1035

Marcin
Marcin

Reputation: 238975

You can use IntEnum:

from enum import IntEnum

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


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

To get list of the ints:

enum_list = list(map(int, Color))
print(enum_list) # prints [1, 2]

Upvotes: 77

Related Questions