Simple(r) enums.
A (mostly) API-compatible re-implementation of
enum.Enum
from the
stdlib (plus related code).
The goal for this module was to try and re-implement as much of the API of
enum.Enum
as possible while using modern Python features. While this does lead
to some API breakage (e.g. type(enum.member) == type(enum)
is no longer true),
it mostly revolves around metaclass-level details. If you rely on the surface
API for enum.Enum
, then this module should be compatible.
Using the example enum:
class Colour(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
The compatibility with enum.Enum
is:
Feature | Supported? |
---|---|
repr(Colour.RED) |
✅ |
str(Colour.RED) |
✅ |
type(Colour.RED) |
❌ (Member instead) |
isinstance(Colour.RED, Colour) |
✅ |
iter(Colour) |
✅ |
hash(Colour.RED) |
✅ |
Colour(1) |
✅ |
Colour["RED"] |
✅ |
Colour.RED in Colour |
✅ |
Colour.RED.name |
✅ |
Colour.RED.value |
✅ |
auto() |
✅ |
_generate_next_value_() |
✅ |
Colour.__members__ |
✅ |
Colour.RED == Colour.RED |
✅ |
Restricted subclassing | ❌ |
Pickling | ✅ |
Functional API | ✅ (via create() ) |
Unfortunately, type checkers hard-code their support for enum.Enum
. That means
they do not recognize members of basicenum.compat.Enum
as being instances of
Member
or matching the API of members of enum.Enum
.
Luckily, you can lie to the type checkers. You can tell them to type check as if
you're using enum
while using basicenum.compat
during execution.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from enum import Enum, auto
else:
from basicenum.compat import Enum, auto
If you install the [benchmark]
extra, you can use
richbench
to see a performance
comparison between enum
and basicenum.compat
.
Using a AMD Ryzen™ 7 7840U w/ Radeon™ 780M Graphics × 16 w/ Python 3.12.1:
richbench --markdown --repeat 5 --times 5 --benchmark compat benchmarks/
Benchmarks, repeat=5, number=5
Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |
---|---|---|---|---|---|---|
import | 0.411 | 0.416 | 0.413 | 0.041 (10.1x) | 0.050 (8.3x) | 0.043 (9.5x) |
creation w/ auto() |
0.221 | 0.225 | 0.223 | 0.046 (4.8x) | 0.047 (4.8x) | 0.046 (4.8x) |
_generate_next_value_() |
0.184 | 0.186 | 0.185 | 0.053 (3.5x) | 0.053 (3.5x) | 0.053 (3.5x) |
creation w/ constants | 0.156 | 0.157 | 0.157 | 0.041 (3.8x) | 0.042 (3.8x) | 0.041 (3.8x) |
functional API | 0.181 | 0.183 | 0.182 | 0.042 (4.3x) | 0.043 (4.2x) | 0.043 (4.3x) |
isinstance(..., Enum) | 0.039 | 0.039 | 0.039 | 0.119 (-3.1x) | 0.121 (-3.1x) | 0.120 (-3.1x) |
iter(Enum) |
0.282 | 0.284 | 0.283 | 0.094 (3.0x) | 0.096 (3.0x) | 0.095 (3.0x) |
Enum(...) |
0.109 | 0.110 | 0.110 | 0.053 (2.1x) | 0.055 (2.0x) | 0.053 (2.1x) |
Enum[...] |
0.025 | 0.026 | 0.026 | 0.025 (1.0x) | 0.027 (-1.1x) | 0.026 (-1.0x) |
... in Enum |
0.036 | 0.036 | 0.036 | 0.068 (-1.9x) | 0.069 (-1.9x) | 0.068 (-1.9x) |
member access | 0.066 | 0.068 | 0.067 | 0.067 (-1.0x) | 0.067 (1.0x) | 0.067 (-1.0x) |
value access | 0.225 | 0.230 | 0.228 | 0.044 (5.1x) | 0.044 (5.2x) | 0.044 (5.2x) |
equality | 0.064 | 0.064 | 0.064 | 0.063 (1.0x) | 0.064 (-1.0x) | 0.064 (1.0x) |
repr | 0.118 | 0.119 | 0.118 | 0.093 (1.3x) | 0.093 (1.3x) | 0.093 (1.3x) |
str | 0.067 | 0.067 | 0.067 | 0.061 (1.1x) | 0.061 (1.1x) | 0.061 (1.1x) |
hashing | 0.103 | 0.103 | 0.103 | 0.103 (-1.0x) | 0.104 (-1.0x) | 0.103 (-1.0x) |
pickling | 0.113 | 0.114 | 0.114 | 0.113 (1.0x) | 0.113 (1.0x) | 0.113 (1.0x) |
unpickling | 0.109 | 0.111 | 0.109 | 0.109 (1.0x) | 0.109 (1.0x) | 0.109 (1.0x) |
__members__ |
0.126 | 0.128 | 0.127 | 0.027 (4.7x) | 0.028 (4.5x) | 0.027 (4.7x) |
@unique |
0.270 | 0.274 | 0.273 | 0.058 (4.7x) | 0.061 (4.5x) | 0.059 (4.6x) |
The class to inherit from to create an enum.
The class which all enum members are instances of.
Function for automatic, incrementing integer member values.
Guarantee that all enum members have unique values.
Raises ValueError
if values are not all unique.
A re-implementation of the functional API of enum.Enum
.
def create(
enum_name, member_names, /, *, module=None, qualname=None, type=None, start=1
): ...