支持 Python 枚举中的未知值

rra*_*alf 6 python inheritance enums

我想扩展 Python 枚举以支持未定义的值。

我的用例:我想从 Enums 中受益(例如,能够用说话的名字来寻址/比较已知条目),但我也希望它支持未知值。如果值后面没有名称, str 应该简单地打印值的 str 表示并且比较应该失败。

让我给你一个简短的例子,我想要什么:

from enum import Enum

class Foo(Enum):
    A = 1
    B = 2
    C = 3

    def __str__(self):
        return self.name


print(Foo(1)) # prints 'A'
print(Foo(2)) # print 'B'
print(Foo(3)) # prints 'C'
print(Foo(1) == Foo.A) # prints 'true'

print(Foo(4)) # I'd expect '4'
print(Foo(123)) # I'd expect '123'
print(Foo(123) == Foo.A) # I'd expect False
Run Code Online (Sandbox Code Playgroud)

当然,最后几行失败了。

有没有办法扩展枚举,或者是否有另一种简单的 Pythonic 方法?(请不要使用第三方库。)

For*_*Bru 3

这是适用于 Python 3.6、3.73.8另一个答案。

它涉及奇怪的元类黑客行为,所以要小心。

import enum

class TestMeta(enum.EnumMeta):
    def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
        if names is not None:
            # the enum is being constructed via the functional syntax
            return super().__call__(value, names=names, module=module, qualname=qualname, type=type, start=start)

        try:
            # attempt to get an enum member
            return super().__call__(value, names=names, module=module, qualname=qualname, type=type, start=start)
        except ValueError:
            # no such member exists, but we don't care
            return value

class Test(enum.Enum, metaclass=TestMeta):
    A = 5
    B = 6    

print(Test(5), Test(6), Test(7))
Run Code Online (Sandbox Code Playgroud)

该版本适用于 Python 2.7,但需要第三方库enum(请参阅评论):

class TestMeta(enum.EnumMeta):
    def __call__(cls, value, names=None, module=None, type=None, start=1):
        if names is not None:
            return enum.EnumMeta.__call__(cls, value, names, module, type, start)

        try:    
            return enum.EnumMeta.__call__(cls, value, names, module, type, start)
        except ValueError:
            return value
Run Code Online (Sandbox Code Playgroud)