I have an Enum
class in Python 3.7 defined as such:
# activation functions
def relu(x: float) -> float:
return x * (x > 0)
def sigmoid(x: float) -> float:
return 1 / (1 + math.exp(-x))
class Activation(Enum):
SIGMOID = sigmoid
RELU = relu
def __call__(self, x):
return self.value(x)
@classmethod
def values(cls):
return [function.value for function in cls]
I have tried some approaches from other similar questions online, like list(Activation)
and Activation.values()
but always get an empty list. Any new ideas?
There's one way to solve this that wasn't mentioned in the linked post without using functools
, staticmethod
, or a wrapper function.
The problem using a function definition as the only value of the Enum member, is that the Enum's __init__
and __new__
never get called. Having additional values, the Enum does get initialized as usual.
Proof as follows:
import math
from enum import Enum
def relu(x: float) -> float:
return x * (x > 0)
def sigmoid(x: float) -> float:
return 1 / (1 + math.exp(-x))
class Activation(Enum):
SIGMOID = 1, sigmoid
RELU = 2, relu
def __init__(self, *args):
self.your_func = args[1]
def __call__(self, x):
return self.your_func(x)
@classmethod
def values(cls):
return [member.your_func for member in cls]
print(Activation.SIGMOID(2))
print(Activation.RELU(2))
# 0.8807970779778823
# 2
for one_func in Activation.values():
print(one_func(2))
# 0.8807970779778823
# 2
I don't think this is a bug (as suggested in the comments) because:
However the issue with functions is that they are considered to be method definitions instead of attributes
What the several solutions have in common is encapsulating the function definition during the Enum (class syntax) value declaration.
Because of the above, using a "wrapper function" without staticmethod
or functools
wouldn't work, because it would never be called. Try substituting the following (neither __init__
not __call__
would be called):
SIGMOID = sigmoid
RELU = relu
def __call__(self, *args, **kwargs):
print("inside")
return self.f(*args, **kwargs)
In conclusion, perhaps the most pythonic approach is wrapping the function definition in a list at declaration, and unwrapping in __init__
at initialization:
import math
from enum import Enum
def relu(x: float) -> float:
return x * (x > 0)
def sigmoid(x: float) -> float:
return 1 / (1 + math.exp(-x))
class Activation(Enum):
SIGMOID = [sigmoid]
RELU = [relu]
def __init__(self, your_func):
self.your_func = your_func[0]
def __call__(self, x):
return self.your_func(x)
@classmethod
def values(cls):
return [member.your_func for member in cls]
print(Activation.SIGMOID(2))
print(Activation.RELU(2))
# 0.8807970779778823
# 2
for one_func in Activation.values():
print(one_func(2))
# 0.8807970779778823
# 2
Which saves calling staticmethod
(some consider its use unpythonic outside a class definition). And saves importing and calling functools.partial
- it involves unnecessary function call overhead with every member access.
Thus, the above approach might arguably be the most pythonic solution.