在Python中,如何正确定义引用子类属性的父类的类方法?
from enum import Enum
class LabelledEnum(Enum):
@classmethod
def list_labels(cls):
return list(l for c, l in cls.__labels.items())
class Test(LabelledEnum):
A = 1
B = 2
C = 3
__labels = {
1: "Label A",
2: "Custom B",
3: "Custom label for value C + another string",
}
print(Test.list_labels())
# expected output
# ["Label A", "Custom B", "Custom label for value C + another string"]
在上面的代码中,我希望
Test.list_labels()
能够正确打印出标签,但是因为 __labels
字典是用双下划线定义的,所以我无法正确访问它。
我想要双下划线的原因是为了确保在迭代枚举器时不会显示标签,例如list(Test) 不应显示包含标签的字典。
如果您使用的是 Python >= 3.11,最好的选择是使用
enum.nonmember
和 单下划线:
In [8]: import enum
...:
...: class LabelledEnum(enum.Enum):
...: @classmethod
...: def list_labels(cls):
...: return list(l for c, l in cls._labels.items())
...:
...:
...: class Test(LabelledEnum):
...: A = 1
...: B = 2
...: C = 3
...:
...: _labels = enum.nonmember({
...: 1: "Label A",
...: 2: "Custom B",
...: 3: "Custom label for value C + another string",
...: })
...:
In [9]: list(Test)
Out[9]: [<Test.A: 1>, <Test.B: 2>, <Test.C: 3>]
In [10]: Test.list_labels()
Out[10]: ['Label A', 'Custom B', 'Custom label for value C + another string']
class Test(LabelledEnum):
A = 1
B = 2
C = 3
_ignore_ = ["_labels"]
_labels = {
1: "Label A",
2: "Custom B",
3: "Custom label for value C + another string",
}
@classmethod
def list_labels(cls):
labels = getattr(cls, f"_{cls.__name__}__labels"
return list(labels.values())
你可以做一些非常丑陋的事情,比如:
getattr(cls, f"_{cls.__name__}__labels", {})
我不确定它是否保证在所有情况下都有效。
from enum import Enum
class LabelledEnum(Enum):
@classmethod
def list_labels(cls):
# account for private name mangling
labels = getattr(cls, f"_{cls.__name__}__labels", {})
return list(l for c, l in labels.items())
虽然
getattr
方法有效,但更优雅的解决方案是使 LabelledEnum
成为混合项,并使用值定义标签:
from enum import Enum
class LabelledEnumMixin:
labels = {}
def __new__(cls, value, label):
member = object.__new__(cls)
member._value_ = value
member.label = label
cls.labels[value] = label
return member
@classmethod
def list_labels(cls):
return list(l for c, l in cls.labels.items())
class Test(LabelledEnumMixin, Enum):
A = 1, "Label A"
B = 2, "Custom B"
C = 3, "Custom label for value C + another string"
披露:我是 Python stdlib
Enum
、enum34
backport 和 Advanced Enumeration (aenum
) 库的作者。