python - Flag 枚举中所有值的表示

标签 python python-3.x enums python-3.6

我想在我的 python Flags 枚举中有一个“ALL”标志

myenum.EVERY_MEMBER & myenum.ALL == myenum.EVERY_MEMBER

成立。我目前有:

from enum import Flag, auto

class RefreshFlags(Flag):
    NONE = 0
    EVENTS = auto()
    RESOURCES = auto()
    BUILDINGS = auto()
    DEFENSES = auto()
    .....

因为这个枚举可能会在任何开发状态下增长,所以我想要类似的东西

@property
def ALL(self):
    retval = self.NONE
    for member in self.__members__.values():
        retval |= member
    return retval

这不起作用:

RefreshFlags.EVENTS  & RefreshFlags.ALL

TypeError: unsupported operand type(s) for &: 'RefreshFlags' and 'property'

请注意,此问题目前仅与 python 3.6 或更高版本有关。

最佳答案

有几种方法可以解决这个问题:


使用类属性方法需要注意的一件事是,由于描述符是在类而不是元类上定义的,因此不存在针对设置和删除的通常保护措施——换句话说:

>>> RefreshFlags.ALL
<RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

>>> RefreshFlags.ALL = 'oops'
>>> RefreshFlags.ALL
'oops'

创建一个新的基类:

# lightly tested
from enum import Flag, auto
from operator import or_ as _or_
from functools import reduce

class AllFlag(Flag):

    @classproperty
    def ALL(cls):
        cls_name = cls.__name__
        if not len(cls):
            raise AttributeError('empty %s does not have an ALL value' % cls_name)
        value = cls(reduce(_or_, cls))
        cls._member_map_['ALL'] = value
        return value

并在使用中:

class RefreshFlag(AllFlag):
    EVENTS = auto()
    RESOURCES = auto()
    BUILDINGS = auto()
    DEFENSES = auto()

>>> RefreshFlag.ALL
<RefreshFlag.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

ALL 属性中有趣的区别在于 _member_map_ 中名称的设置——这允许为 Enum 成员提供相同的保护:

>>> RefreshFlag.ALL = 9
Traceback (most recent call last):
  ....
AttributeError: Cannot reassign members.

但是,这里有一个竞争条件:如果 RefreshFlag.ALL = ... 发生在 RefreshFlag.ALL 被激活的第一个时间然后它被破坏了;出于这个原因,我会在这种情况下使用装饰器,因为装饰器会在 Enum 被破坏之前对其进行处理。

# lightly tested

from enum import Flag, auto
from operator import or_ as _or_
from functools import reduce

def with_limits(enumeration):
    "add NONE and ALL psuedo-members to enumeration"
    none_mbr = enumeration(0)
    all_mbr = enumeration(reduce(_or_, enumeration))
    enumeration._member_map_['NONE'] = none_mbr
    enumeration._member_map_['ALL'] = all_mbr
    return enumeration

并在使用中:

@with_limits
class RefreshFlag(Flag):
    EVENTS = auto()
    RESOURCES = auto()
    BUILDINGS = auto()
    DEFENSES = auto()

>>> RefreshFlag.ALL = 99
Traceback (most recent call last):
  ...
AttributeError: Cannot reassign members.

>>> RefreshFlag.ALL 
<RefreshFlag.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

>>> RefreshFlag.NONE
<RefreshFlag.0: 0>

关于python - Flag 枚举中所有值的表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42251081/

相关文章:

python - 对这个数据帧进行下采样我哪里出了问题?

c++ - 枚举作为模板

python - 如何使用带有 Pandas 数据帧的请求来创建多个 Get http 请求?

python - 在 Python 中递归求解数学方程

python - 如何同步Google电子表格中的计算机本地数据?

python - 刽子手 |使用名字和姓氏作为 "word"的问题

python - 使用 QTextCharFormat 更改选择颜色

python - 在 os x Lion 上运行 python 程序

android - 在 Room 中编写基于某个枚举值进行选择的类型安全查询

RawRepresentable 上的 Swift 扩展没有可访问的初始化器