带有函数值的Python 3枚举

C. *_*oew 11 python enums python-3.x

我注意到Python 3 Enums(链接)中的一个奇怪之处.
如果将Enum的值设置为函数,则会阻止将该属性包装为Enum对象,这会阻止您使用类似EnumCls['AttrName']动态加载属性的酷功能.

这是一个错误吗?有意进行了吗?
我搜索了一段时间,但没有提到你可以在枚举中使用的限制值.

以下是显示问题的示例代码:

class Color(Enum):
    Red = lambda: print('In Red')
    Blue = lambda: print('In Blue')

print(Color.Red)    # <function> - should be Color.Red via Docs
print(Color.Blue)   # <function> - should be Color.Bluevia Docs
print(Color['Red']) # throws KeyError - should be Color.Red via Docs
Run Code Online (Sandbox Code Playgroud)

此外,这是我第一次询问,所以让我知道是否有什么我应该做的不同!谢谢你的帮助!

Bre*_*arn 10

文件说:

允许的规则如下:_sunder_名称(以单个下划线开头和结尾)由enum保留,不能使用; 枚举中定义的所有其他属性将成为此枚举的成员,但__dunder__名称和描述符除外(方法也是描述符).

"方法"只是在类体内定义的函数.无论您是用lambdaor 定义它都无关紧要def.所以你的例子是这样的:

class Color(Enum):
    def Red():
        print('In Red')
    def Blue():
        print('In Blue')
Run Code Online (Sandbox Code Playgroud)

换句话说,你声称的枚举值实际上是方法,因此不会成为枚举的成员.

  • @BrenBarn我认为OP过早地接受了这个答案。枚举上的链接文档指出“枚举可以具有任意值”,只要它们遵循命名限制即可。既然OP没有违反命名限制,为什么OP无法将函数指定为枚举的值呢? (3认同)

Cep*_*o93 6

如果有人需要/想要使用带有函数作为值的 Enum,可以通过使用可调用对象作为代理来实现,如下所示:

class FunctionProxy:
    """Allow to mask a function as an Object."""
    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        return self.function(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

一个简单的测试:

from enum import Enum
class Functions(Enum):
    Print_Function = FunctionProxy(lambda *a: print(*a))
    Split_Function = FunctionProxy(lambda s, d='.': s.split(d))

Functions.Print_Function.value('Hello World!')
# Hello World!
Functions.Split_Function.value('Hello.World.!')
# ['Hello', 'World', '!']
Run Code Online (Sandbox Code Playgroud)

  • 另一种策略是使用“functools.partial”,这样可以避免定义新类。 (2认同)

K3-*_*rnc 6

您可以将这些lambda包装在元组中并覆盖该__call__方法:

class Color(Enum):
    red = (lambda text: '<font color=red>%s</font>' % text,)
    blue = (lambda text: '<font color=blue>%s</font>' % text,)

    def __call__(self, *args, **kwargs):
        return self.value[0](*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

然后可以使用:

>>> Color.red('flowers')
<font color=red>flowers</font>
Run Code Online (Sandbox Code Playgroud)


Dar*_*n84 6

您还可以使用functools.partial欺骗枚举不将您的函数视为以下方法Color

from functools import partial
from enum import Enum

class Color(Enum):
    Red = partial(lambda: print('In Red'))
    Blue = partial(lambda: print('In Blue'))
Run Code Online (Sandbox Code Playgroud)

这样您就可以按预期name访问。value

Color.Red
Out[17]: <Color.Red: functools.partial(<function Color.<lambda> at 0x7f84ad6303a0>)>
Color.Red.name
Out[18]: 'Red'
Color.Red.value()
In Red
Run Code Online (Sandbox Code Playgroud)