我正在学习如何在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
的价值?
如果要将属性映射到字符串,请不要使用枚举类。 enum
模块的重点是生成一组表示枚举的单例对象,而不是字符串。从模块文档:
枚举是一组绑定到唯一常量值的符号名称(成员)。在枚举中,可以通过标识来比较成员,并且可以迭代枚举本身。)
大胆强调我的。字符串不是唯一的,恒定的值(我可以随意创建更多的"Fido"
字符串)并且不是为了通过身份进行比较(即使sometimes, for a subset of strings, you can)。
只需直接使用属性作为字符串定义您自己的类:
class Pets:
DOG = "Fido"
CAT = "Kitty"
您的无限递归错误是由于您对该方法的用途存在误解而引起的。像all special methods一样,object.attr
在对象类型上查找__getattr__
,这意味着你的方法适用于你的Enum
子类的实例,这里的DOG
和CAT
属性,而不是类本身,并且干扰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'
。