如何直接作为类属性访问Enum的值?

问题描述 投票:0回答:1

我正在学习如何在Python中使用Enum类,并且发现每当我需要访问枚举的实际值时,我需要附加.value属性:

from enum import Enum
class Pets(Enum):
    DOG = "Fido"
    CAT = "Kitty"

Pets.DOG # yields Pets.DOG
Pets.DOG.value # yields Fido

作为练习,我正在尝试配置我的Enum类,以便我不需要不断访问value属性。我希望的行为是,当我打电话给Pets.DOG时,我得到Fido作为我的价值。

我试图用__getattr_(cls, item)实现这个:

class Pets(Enum):

    def __getattr__(self, item):
        print(f"__getattr__ called with {item}")
        return getattr(self, item).value

    DOG = "Fido"
    CAT = "Kitty"


if __name__ == "__main__":

    pets = Pets()
    pets.DOG

但是,我收到了RecursionError: maximum recursion depth exceeded while calling a Python object,而item_value_的字符串值。我不太明白为什么会发生这种情况 - 这是内置的Python行为,还是因为我使用的是特殊的类Enum

我确实看了一个类似的SO帖子,但是那里的解决方案是使用另一个模块(inspect),或访问__dict__dir()并使用条件语或正则表达式的组合自己解析。有没有更好的方法来获取潜在的Enum的价值?

python enums
1个回答
3
投票

如果要将属性映射到字符串,请不要使用枚举类。 enum模块的重点是生成一组表示枚举的单例对象,而不是字符串。从模块文档:

枚举是一组绑定到唯一常量值的符号名称(成员)。在枚举中,可以通过标识来比较成员,并且可以迭代枚举本身。)

大胆强调我的。字符串不是唯一的,恒定的值(我可以随意创建更多的"Fido"字符串)并且不是为了通过身份进行比较(即使sometimes, for a subset of strings, you can)。

只需直接使用属性作为字符串定义您自己的类:

class Pets:
    DOG = "Fido"
    CAT = "Kitty"

您的无限递归错误是由于您对该方法的用途存在误解而引起的。像all special methods一样,object.attr在对象类型上查找__getattr__,这意味着你的方法适用于你的Enum子类的实例,这里的DOGCAT属性,而不是类本身,并且干扰EnumMeta元类试图测试_value_ attibute,由你的__getattr__方法处理,self是新建的Pets.DOG实例,item设置为'_value_',然后调用getattr(Pets.DOG, '_value_'),调用__getattr__等。

对于你的工作方法,你必须子类化EnumMeta并在该子类上实现__getattribute____getattr__只被用于缺少属性)。但是,考虑到__getattribute__用于所有属性访问,因此您必须首先检查当前类的实例:

class EnumDirectValueMeta(EnumMeta):
    def __getattribute__(cls, name):
        value = super().__getattribute__(name)
        if isinstance(value, cls):
            value = value.value
        return value

class Pets(Enum, metaclass=EnumDirectValueMeta):
    DOG = "Fido"
    CAT = "Kitty"

在这一点上Pets.DOG生产'Fido'

© www.soinside.com 2019 - 2024. All rights reserved.