Reputation: 6350
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
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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