如何正确定义访问损坏子属性值的类方法?

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

在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 enums python-class
3个回答
3
投票

如果您使用的是 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']
如果您至少使用 Python 3.7,则可以使用枚举特定的“sunder”名称,并将“_lables”添加到忽略列表中:
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",
    }
另一种方法是动态构建字符串,虽然它很笨重,但它会起作用(坦率地说,“enum”应该忽略*单*下划线,而不是双下划线,但可惜):
@classmethod
def list_labels(cls):
    labels = getattr(cls, f"_{cls.__name__}__labels"
    return list(labels.values())

2
投票

你可以做一些非常丑陋的事情,比如:

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())

2
投票

虽然

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
)
库的作者。

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