让我们说Color类是一个枚举:
from enum import IntEnum
class Color(IntEnum):
red = 1
blue = 2
green = 3
现在,让我们说我希望将每个成员与一个功能相关联并保持其价值。即做这样的事情
Colors.red()
会调用我以某种方式分配的功能。 并保持IntEnum行为,意味着
Colors.red == 1
仍会返回True
我想我需要为枚举定义一个新的超类,但是如何?
我唯一能做到的就是:
class Colors(Enum):
red = (1, f)
blue = (2, g)
green = (3, h)
其中f
g
和h
是函数。
然而。使用此方法,访问该值的唯一方法是
Colors.red.value[0]
要调用该函数,这是
Colors.red.value[1](args)
在我看来,这很丑陋,尤其是当名字有点长,当你需要多次调用函数并且有很多参数时
那么有没有办法做我想做或做的事我需要坚持使用uggly版本?
答案 0 :(得分:2)
简单明了,虽然是可读性和可理解性的噩梦。通过提供__call__
方法简单地实现Python可调用接口。将它埋在某个模块中,实现__all__
并且永远不会导入除Color
类之外的任何内容。
from enum import IntEnum
f1 = lambda x: x
f2 = lambda x: x*x
f3 = lambda x: x*x*x
class Color(IntEnum):
red = 1
blue = 2
green = 3
def __call__(self, *args, **kwargs):
# alternatively some generic function of self.value
return LUT[self](*args, **kwargs)
LUT = {Color.red: f1, Color.blue: f2, Color.green: f3}
assert Color.red(1) == 1
assert Color.blue(2) == 4
assert Color.green(3) == 27
assert Color.blue > Color.red
编辑: 更好(更可读,更少hacky等)将在Enum上定义显式可调用接口。
class Color(IntEnum):
red = 1
blue = 2
green = 3
def get_something(self, x):
# e.g.
return x ** self.value
此枚举的任何用户都会执行以下操作:
o = Obj()
o.color.get_something(123)
使用get_something
的正确名称可读,易于理解pylint和其他静态分析工具,并且不易出错。
答案 1 :(得分:1)
反对我更好的判断,我决定解开将Enum
组合在一起的神奇线索。这就是我想出的:
from enum import Enum
class FuncEnum(Enum):
def __init__(self, val, func=None):
self.val = val
self.func = func or lambda: None
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def __eq__(self, other):
return self.val == other
def __ge__(self, other):
return self.val >= other
# and etc... not sure how @total_ordering will work here!
class Color(FuncEnum):
red = (1, lambda x: x**2)
blue = (2, lambda x: x**3)
green = (3, lambda x: x**4)
Color.red(4) # 16
Color.red == 1 # True
Color.blue(2) # 8
这也支持重新分配,所以事后:
Color.red.func = str.lower
Color.red("LOWERCASE") # "lowercase"