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

我正在学习如何Enum在 Python 中使用类,并发现每当我需要访问枚举的实际值时,我都需要附加.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__ordir()并使用条件或正则表达式的组合自己解析它。有没有更好的方法来获取底层证券Enum的价值?


aluckdog
浏览 208回答 2
2回答

交互式爱情

如果要将属性映射到字符串,请不要使用 enum 类。整点的的enum模块是产生一组表示一个枚举单一对象,而不是串。从模块文档:枚举是一组绑定到唯一常量值的符号名称(成员)。在枚举中,成员可以通过 identity 进行比较,并且枚举本身可以迭代。)大胆强调我的。字符串不是唯一的常量值(我可以随意创建更多"Fido"字符串)并且不是为了通过身份进行比较而设计的(即使有时,对于字符串的子集,您可以)。只需直接使用字符串属性定义您自己的类:class Pets:    DOG = "Fido"    CAT = "Kitty"您的无限递归错误是由您对该方法用途的误解引起的。像所有的专用方法,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 valueclass Pets(Enum, metaclass=EnumDirectValueMeta):    DOG = "Fido"    CAT = "Kitty"此时Pets.DOG产生'Fido'.

qq_花开花谢_0

你说,“我想要的行为是,当我打电话时Pets.DOG,我把 Fido 作为我的价值。” CallingPets.DOG真的是 call print(repr(Pets.DOG)),所以我的建议是这样的:class Pets(enum.Enum):    DOG = "Fido"    CAT = "Kitty"        def __repr__(self):        return self.value这种方法的一个优点是您仍然可以访问 Enum 的其他功能,例如 Pets.DOG.name也就是说,我更愿意覆盖__str__而不是__repr__因为这可以实现您避免输入的目标.value,但Enum在使用repr().我在尝试对我的值使用命名元组而不是简单字符串时遇到了您的问题。在这种情况下,我认为__getattr__是有帮助的,以防万一其他人发现这篇文章有类似的用途,我将包括对我有用的内容:import enumimport collections_ = lambda x : xclass XlateEnum(enum.Enum):    """Enum whose members inherit the attributes of their values,         and which applies the assumed function _() for translations.     """        def __getattr__(self, name):        if name == "_value_":            return enum.Enum.__getattribute__(self, name)        elif hasattr(self, "_value_") and hasattr(self._value_, name):                return _(getattr(self._value_, name))        return enum.Enum.__getattribute__(self, name)            def __setattr__(self, name, new_value):        if name == "_value_":            enum.Enum.__setattr__(self, name, new_value)        elif hasattr(self, "_value_") and hasattr(self._value_, name):            raise AttributeError("can't set attribute")        else:            enum.Enum.__setattr__(self, name, new_value)                def __delattr__(self, name):        if hasattr(self, "_value_") and hasattr(self._value_, name):            raise AttributeError("can't delete attribute")        else:            enum.Enum.__delattr__(self, name)                def __str__(self):        return self.str if hasattr(self, "str") else _(enum.Enum.__str__(self.value))    class Pet(XlateEnum):    """My pets.     Attributes:        str: A localized str to name the Pet. How the Pet prints.        my: A string representing what I call instances of this Pet.        legs: The int number of legs of normal instances of this Pet.    """                  DOG = collections.namedtuple("PetValue", "str my legs")(_("Dog"), "Fido", 4)    CAT = collections.namedtuple("PetValue", "str my legs")(_("Cat"), "Kitty", 4)      print(Pet.DOG)    # yields "Dog" (or translated string)print(Pet.DOG.my) # yields "Fido" (which is not designated for translation)当然,您可以删除该_()功能。我发现Enum和namedtuple对常量非常有用,因为它使它们彼此保持适当的关系,而且我喜欢将我所有的翻译功能构建到常量本身中,所以这样的代码才有效:import ipywidgetsipywidgets.Dropdown(options=Pet) 
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python