Enums are great. They allow you cleanly define a set of statically defined
options.

One way that I've found myself using enums recently is for dispatching (as
keys in a dictionary) between different interchangeable functions or
classes. My code looks something like this:

from enum import Enum

def foo(...):
    ...

def bar(...):
    ...

class Implementation(Enum):
    FOO = 1
    BAR = 2

_IMPLEMENTATIONS = {
    Implementation.FOO: foo,
    Implementation.BAR: bar,
}

def call_implementation(implementation, *args, **kwargs):
    return _IMPLEMENTATIONS[implementation](*args, **kwargs)

The first part of this blog post does a nice job of summarizing the general
use case:
http://lukasz.langa.pl/8/single-dispatch-generic-functions/

Obviously, enums are better than strings, because they're static declared
and already grouped together. But it would be nice if we could do one
better, by eliminating the dictionary, moving the dictionary values to the
enum and making the enum instances.

You might try this by writing a small subclass of Enum:

class CallableEnum(Enum):
    def __call__(self, *args, **kwargs):
        return self.value(*args, **kwargs)

class Implementation(CallableEnum):
    FOO = foo
    BAR = bar

def call_implementation(implementation, *args, **kwargs):
    return implementation(*args, **kwargs)

This looks great, with the Enum serving essentially as a typed namespace
for a group of related functions, but unfortunately it this doesn't work.
The problem is that when you assign a function to an Enum, it treats it as
a method instead of an enum value:
http://stackoverflow.com/questions/40338652/how-to-define-enum-values-that-are-functions

Instead, you need to wrap function values in a callable class, e.g.,

from functools import partial

class Implementation(CallableEnum):
    FOO = partial(foo)
    BAR = partial(bar)

This is OK, but definitely uglier and more error prone than necessary. It's
easy to forget to add a partial, which results in an accidental method
declaration.

It would be nice to have a CallableEnum class that works like Enum, but
adds the __call_ method and doesn't allow defining any new methods: all
functions assigned in the class body become Enum instances instead of
methods.

I would write this myself and throw it up on pypi, but there doesn't seem
to be any way to do this short of delving into the guts of enum.EnumMeta
<https://github.com/python/cpython/blob/0dc5c3169dcd4853612d11ed8c92b12fa210c07f/Lib/enum.py#L93>.
Given that I think that others will also find this pattern useful, rather
than forking the enum module I would like to add this into the standard
library instead.

Note: this proposal would also allow defining enum values using "def"
inside the Enum body. But I think this is actually pretty clean, aside from
general enum confusion over the fact that Implementation.FOO is Enum
instance, not the method.

class Implementation(CallableEnum):
    def FOO(...):
        ...
    def BAR(...):
        ...
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to