Nic*_*ton 13 python enums function
我有一种情况需要强制执行,并为用户提供多个select函数之一的选项,作为参数传递给另一个函数:
我真的想要实现以下内容:
from enum import Enum
#Trivial Function 1
def functionA():
pass
#Trivial Function 2
def functionB():
pass
#This is not allowed (as far as i can tell the values should be integers)
#But pseudocode for what I am after
class AvailableFunctions(Enum):
OptionA = functionA
OptionB = functionB
Run Code Online (Sandbox Code Playgroud)
所以可以执行以下操作:
def myUserFunction(theFunction = AvailableFunctions.OptionA):
#Type Check
assert isinstance(theFunction,AvailableFunctions)
#Execute the actual function held as value in the enum or equivalent
return theFunction.value()
Run Code Online (Sandbox Code Playgroud)
Bak*_*riu 25
你的假设是错误的.值可以是任意的,它们并不限于整数.从文档:
上面的示例使用整数来表示枚举值.使用整数简短而方便(并且由Functional API默认提供),但不严格执行.在绝大多数用例中,人们并不关心枚举的实际价值.但是,如果值很重要,枚举可以具有任意值.
然而,函数的问题是它们被认为是方法定义而不是属性!
In [1]: from enum import Enum
In [2]: def f(self, *args):
...: pass
...:
In [3]: class MyEnum(Enum):
...: a = f
...: def b(self, *args):
...: print(self, args)
...:
In [4]: list(MyEnum) # it has no values
Out[4]: []
In [5]: MyEnum.a
Out[5]: <function __main__.f>
In [6]: MyEnum.b
Out[6]: <function __main__.MyEnum.b>
Run Code Online (Sandbox Code Playgroud)
你可以通过使用包装类或只是解决这个问题functools.partial:
from functools import partial
class MyEnum(Enum):
OptionA = partial(functionA)
OptionB = partial(functionB)
Run Code Online (Sandbox Code Playgroud)
样品运行:
In [7]: from functools import partial
In [8]: class MyEnum2(Enum):
...: a = partial(f)
...: def b(self, *args):
...: print(self, args)
...:
In [9]: list(MyEnum2)
Out[9]: [<MyEnum2.a: functools.partial(<function f at 0x7f4130f9aae8>)>]
In [10]: MyEnum2.a
Out[10]: <MyEnum2.a: functools.partial(<function f at 0x7f4130f9aae8>)>
Run Code Online (Sandbox Code Playgroud)
或者使用包装类:
In [13]: class Wrapper:
...: def __init__(self, f):
...: self.f = f
...: def __call__(self, *args, **kwargs):
...: return self.f(*args, **kwargs)
...:
In [14]: class MyEnum3(Enum):
...: a = Wrapper(f)
...:
In [15]: list(MyEnum3)
Out[15]: [<MyEnum3.a: <__main__.Wrapper object at 0x7f413075b358>>]
Run Code Online (Sandbox Code Playgroud)
另请注意,如果需要,可以__call__在枚举类中定义方法以使值可调用:
In [1]: from enum import Enum
In [2]: from functools import partial
In [3]: def f(*args):
...: print(args)
...:
In [4]: class MyEnum(Enum):
...: a = partial(f)
...: def __call__(self, *args):
...: self.value(*args)
...:
In [5]: MyEnum.a(1,2,3) # no need for MyEnum.a.value(1,2,3)
(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
从 Python 3.11 开始,有更简洁、更容易理解的方式。member和nonmember功能已添加到enum其他改进中,因此您现在可以执行以下操作:
from enum import Enum, member, nonmember
def fn(x):
print(x)
class MyEnum(Enum):
x = nonmember(1)
meth = fn
mem = member(fn)
@classmethod
def this_is_a_method(cls):
print('No, still not a member')
def this_is_just_function():
print('No, not a member')
@member
def this_is_a_member(x):
print('Now a member!', x)
Run Code Online (Sandbox Code Playgroud)
现在
>>> list(MyEnum)
[<MyEnum.mem: <function fn at ...>>, <MyEnum.this_is_a_member: <function MyEnum.this_is_a_member at ...>>]
>>> MyEnum.meth(1)
1
>>> MyEnum.mem(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyEnum' object is not callable
>>> MyEnum.mem.value(1)
1
>>> MyEnum.this_is_a_method()
No, still not a member
>>> MyEnum.this_is_just_function()
No, not a member
>>> MyEnum.this_is_a_member()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyEnum' object is not callable
>>> MyEnum.this_is_a_member.value(1)
Now a member! 1
>>> MyEnum.x
1
Run Code Online (Sandbox Code Playgroud)
当然,您可以添加__call__以避免显式.value调用:
class MyEnum(Enum):
...
def __call__(self, *args, **kwargs):
return self.value(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
现在
>>> MyEnum.mem(1)
1
Run Code Online (Sandbox Code Playgroud)
请注意,除非所有枚举成员函数共享相同的签名,否则无法正确键入此内容。
另一个不太笨重的解决方案是将函数放在元组中。正如 Bakuriu 提到的,您可能希望使枚举可调用。
from enum import Enum
def functionA():
pass
def functionB():
pass
class AvailableFunctions(Enum):
OptionA = (functionA,)
OptionB = (functionB,)
def __call__(self, *args, **kwargs):
self.value[0](*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
现在你可以像这样使用它:
AvailableFunctions.OptionA() # calls functionA
Run Code Online (Sandbox Code Playgroud)