我正在尝试创建一个带有惰性评估的enum.Enum。
根据医生的说法:
枚举是一组符号名(成员),绑定到唯一的常量值。在枚举中,成员可以通过标识进行比较,枚举本身也可以迭代。
我想说,我的案件仍然属于这个定义的范围。这些值仍然是唯一和不变的,我只希望它们在必要时被初始化。这可能是因为初始化很耗时,依赖于其他Enum成员,与其他Enum具有循环依赖关系,或者(在我当前的例子中)是因为初始化需要一个运行的QGuiApplication,如果一个模块没有运行(当然还有其他方法来绕过这个特定的需求,那么我希望模块仍然是不可输入的(但保持特定的枚举不可用)。
从we are only supposed to subclass EnumMeta in rare cases开始,我想通过子类Enum本身来实现这一点:
class Lazy:
    def __init__(self, value):
        self.value = value
class LazyEnum(Enum):
    def __getattribute__(self, name):
        result = super().__getattribute__(name)
        if name == 'value' and isinstance(result, Lazy):
            result = self._lazy_init(result.value)
            self.__setattr__(name, result)
        return result这样做的目的是将一些值标记为Lazy,以便稍后初始化。但是,我的示例代码:
class MyEnum(LazyEnum):
    X = Lazy('x')
    Y = Lazy('y')
    Z = 'z'
    def _lazy_init(self, value):
        print(f"Evaluating {value}")
        return value * 2
print(MyEnum.X.value)
print(MyEnum.X)
print(MyEnum.X.value)引发错误:
AttributeError: can't set attribute我该怎么解决这个问题?
发布于 2021-02-11 12:56:33
我查看了Enum的源代码,并通过直接设置_value_属性而不是value属性来解决这个问题。这个解决方案让我觉得有些烦躁,但它似乎奏效了:
from abc import ABCMeta, abstractmethod
from enum import Enum, EnumMeta
class AbstractEnumMeta(EnumMeta, ABCMeta):
    pass
class Lazy:
    def __init__(self, *lazy_init_arguments):
        self.args = lazy_init_arguments
class LazyEnum(Enum, metaclass=AbstractEnumMeta):
    def __getattribute__(self, name):
        result = super().__getattribute__(name)
        if name == 'value' and isinstance(result, Lazy):
            result = self._lazy_init(*result.args)
            setattr(self, '_value_', result)
        return result
    @classmethod
    @abstractmethod
    def _lazy_init(cls, *args):
        return args
class MyEnum(LazyEnum):
    X = Lazy('x')
    Y = Lazy('y')
    Z = 'z'
    @classmethod
    def _lazy_init(cls, value):
        print(f"Lazy init of {value}")
        return value * 2
>>> MyEnum.Z
MyEnum.Z
>>> MyEnum.Z.value
'z'
>>> MyEnum.X
MyEnum.X
>>> MyEnum.X.value
Lazy init of x
'xx'
>>> MyEnum.X.value
'xx'https://stackoverflow.com/questions/66108148
复制相似问题