Consider:
class Item:
def __init__(self, a, b):
self.a = a
self.b = b
class Items:
GREEN = Item(\'a\', \'b\')
BLUE = Item(\'c\', \'
Here's another approach which I think is simpler than the others, but allows the most flexibility:
from collections import namedtuple
from enum import Enum
class Status(namedtuple('Status', 'name description'), Enum):
READY = 'ready', 'I am ready to do whatever is needed'
ERROR = 'error', 'Something went wrong here'
def __str__(self) -> str:
return self.name
Works as expected:
print(Status.READY)
print(repr(Status.READY))
print(Status.READY.description)
print(Status.READY.value)
prints:
ready
<Status.READY: Status(name='ready', description='I am ready to do whatever is needed')>
I am ready to do whatever is needed
Status(name='ready', description='I am ready to do whatever is needed')
You get the best of namedtuple and Enum.
For Python 3:
class Status(Enum):
READY = "ready", "I'm ready to do whatever is needed"
ERROR = "error", "Something went wrong here"
def __new__(cls, *args, **kwds):
obj = object.__new__(cls)
obj._value_ = args[0]
return obj
# ignore the first param since it's already set by __new__
def __init__(self, _: str, description: str = None):
self._description_ = description
def __str__(self):
return self.value
# this makes sure that the description is read-only
@property
def description(self):
return self._description_
And you can use it as a standard enum or factory by type:
print(Status.READY)
# ready
print(Status.READY.description)
# I'm ready to do whatever is needed
print(Status("ready")) # this does not create a new object
# ready
Before Python 3.4 and the addition of the excellent enum module, a good choice would have been to use a namedtuple:
from collections import namedtuple
Item = namedtuple('abitem', ['a', 'b'])
class Items:
GREEN = Item('a', 'b')
BLUE = Item('c', 'd')
These days, any supported version of Python has enum
, so please use that module. It gives you a lot more control over how each enum value is produced.
If you give each item a tuple of values, then these are passed to the __init__
method as separate (positional) arguments, which lets you set additional attributes on the enum value:
from enum import Enum
class Items(Enum):
GREEN = ('a', 'b')
BLUE = ('c', 'd')
def __init__(self, a, b):
self.a = a
self.b = b
This produces enum entries whose value is the tuple assigned to each name, as well as two attributes a
and b
:
>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items(('a', 'b'))
<Items.GREEN: ('a', 'b')>
Note that you can look up each enum value by passing in the same tuple again.
If the first item should represent the value of each enum entry, use a __new__
method to set _value_
:
from enum import Enum
class Items(Enum):
GREEN = ('a', 'b')
BLUE = ('c', 'd')
def __new__(cls, a, b):
entry = object.__new__(cls)
entry.a = entry._value_ = a # set the value, and the extra attribute
entry.b = b
return entry
def __repr__(self):
return f'<{type(self).__name__}.{self.name}: ({self.a!r}, {self.b!r})>'
I added a custom __repr__
as well, the default only includes self._value_
. Now the value of each entry is defined by the first item in the tuple, and can be used to look up the enum entry:
>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items('a')
<Items.GREEN: ('a', 'b')>
See the section on __init__ vs. __new__ in the documentation for further options.
Python 3.4 has a new Enum data type (which has been backported as enum34 and enhanced as aenum1). Both enum34
and aenum
2 easily support your use case:
[aenum
py2/3]
import aenum
class EnumWithAttrs(aenum.AutoNumberEnum):
_init_ = 'a b'
GREEN = 'a', 'b'
BLUE = 'c', 'd'
[enum34
py2/3 or stdlib enum
3.4+]
import enum
class EnumWithAttrs(enum.Enum):
def __new__(cls, *args, **kwds):
value = len(cls.__members__) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
def __init__(self, a, b):
self.a = a
self.b = b
GREEN = 'a', 'b'
BLUE = 'c', 'd'
And in use:
--> EnumWithAttrs.BLUE
<EnumWithAttrs.BLUE: 1>
--> EnumWithAttrs.BLUE.a
'c'
1 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.
2 aenum
also supports NamedConstants
and metaclass-based NamedTuples
.