是否可以制作一个 class 来堆叠枚举标志?

Is it possible to make a class which lets you stack enum Flags?

我想尽可能使用命名常量,而不是提供文字值或带有大量布尔参数的冗长函数签名。

因此我喜欢蟒蛇enum.Flagenum.Enum

更准确地说,我想将一个参数传递给一个包含 enum.Flags 位组合的函数。而且我想避免为我想传递给函数的每个设置标志编写 module.TheFlags.flagX 。标志应替换布尔参数。

我想出了以下代码:

import enum


class AvailableFlags(enum.Flag):
    flag1 = enum.auto()
    flag2 = enum.auto()


class FuncFlags:
    def __init__(self):
        self._flags = AvailableFlags(0)

    @property
    def flag1(self):
        self._flags |= AvailableFlags.flag1
        return self

    @property
    def flag2(self):
        self._flags |= AvailableFlags.flag2
        return self

    def __str__(self):
        return str(self._flags.value)


def func(setup_flags: FuncFlags):
    print(setup_flags)


if __name__ == "__main__":
    func(FuncFlags().flag1)
    func(FuncFlags().flag2)
    func(FuncFlags().flag1.flag2)
    func(FuncFlags())

它创建 FuncFlags 的实例,然后 误用 属性来设置返回更改对象本身的单个标志。 但是,人们会期望 属性 不会更改对象状态。 因此,尽管它有效,但这显然不是一个干净的解决方案。

所以,我的问题是,如何以一种干净、可重用的方式实现它?

我不是很清楚你想要完成什么,但也许这有帮助?

import enum

class AvailableFlags(enum.Flag):
    flag1 = enum.auto()
    flag2 = enum.auto()

flag1, flag2 = AvailableFlag


def func(setup_flags: AvailableFlags):
    print(setup_flags)


if __name__ == "__main__":
    func(flag1)
    func(flag2)
    func(flag1|flag2)
    func()

与此同时,我通过添加另一层间接寻址找到了答案。 如果其他人感兴趣,我想在这里分享。 每次调用标志都会通过设置附加标志从当前实例创建一个新实例,从而维护对象状态。 如果我们尝试访问未定义的标志,则会引发异常(未显示)。

import enum


class AvailableFlags(enum.Flag):
    flag1 = enum.auto()
    flag2 = enum.auto()


class FlagHelper:
    def __init__(self, cls, value = 0):
        self._cls = cls
        self._flags = self._cls(value)

    def __getattr__(self, item):
        if item in self._cls.__members__:
            return self.__class__(self._flags | getattr(self._cls, item))

        getattr(self._cls, item)  # Let attribute error pass through

    def __str__(self):
        return str(self._flags.value)


class FuncFlags(FlagHelper):
    def __init__(self, value = 0):
        super().__init__(AvailableFlags, value)


def func(setup_flags: FuncFlags):
    print(setup_flags)


if __name__ == "__main__":
    ff = FuncFlags()
    func(ff.flag1)
    func(ff.flag2)
    func(ff.flag1.flag2)
    func(ff)

输出:

1
2
3
0