The Problem
Suppose I have an enum defined:
from enum import Enum, auto
class Foo(Enum):
DAVE_GROHL = auto()
MR_T = auto()
and I want to extend this class with specific methods only (ie, no new enum members):
class MixinFoo(Foo):
def catch_phrase(self):
if self is Foo.MR_T:
return "I pity da foo!"
else:
return "There goes my hero!"
This will fail with TypeError
, since by design enum's can't be extended once members have been defined. Python enum allows you to do this in the other direction (ie: define mixin with no members and subclass the mixin to add members), but in my specific use case, defining MixinFoo
before Foo
to use as a base class is not an option (eg: Foo
is defined in another module and I don't want to recreate it or modify that module's code).
What I've considered so far:
Tweaking the EnumMeta
. EnumMeta
checks for existing members in the base class in the __prepare__
method, so overriding this method and deferring the check in a new metaclass could work. Unfortunately, EnumMeta
checks for existing members in several other functions, and redefining all those functions seems like bad practice in general (lots of duplicated code).
Adding functions after the fact. I know it's possible to do something like:
def catch_phrase(self):
...
Foo.catch_phrase = catch_phrase
and while this might work, there are some significant disadvantages that I would like to avoid (eg: very cumbersome for a large number of functions, static/class methods, properties of normal class definition might be difficult to implement)
Solving the problem with composition over inheritance:
class FooWrapper():
def __init__(self, foo):
self._foo = foo
def catch_phrase(self):
...
While this is possible, I'm not a huge fan of this method.
Some Related Questions:
Why does EnumMeta
have checks for existing members outside of __prepare__
? From a design perspective, this seems to not only be redundant, but also makes it unnecessarily difficult to extend the EnumMeta
as in my case. I understand the rationale behind not allowing extension of enums with more members, but mixins were obviously considered in the design of the enum library. Was this an oversight in the design of the enum? Was it considered and rejected? Is it intentional for some reason?
Furthermore, one of the checks for existing members is buried in the _EnumDict
class, which is not accessible, so I'm not sure what I'm trying to do is possible without recreating a fairly substantial portion of the enum library.
The overall intent is that I have a common enum where the members are known and fixed, but the use case and methods are application specific (ie, different applications that use Foo
would have different greetings and possibly other functions to add, but no application would need to add other Foo
s).