2 回答
TA贡献1712条经验 获得超3个赞
如果要将属性映射到字符串,请不要使用 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 value
class Pets(Enum, metaclass=EnumDirectValueMeta):
DOG = "Fido"
CAT = "Kitty"
此时Pets.DOG产生'Fido'.
TA贡献1835条经验 获得超7个赞
你说,“我想要的行为是,当我打电话时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 enum
import collections
_ = lambda x : x
class 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 ipywidgets
ipywidgets.Dropdown(options=Pet)
添加回答
举报