表示Flag枚举中的所有值 [英] Representation of all values in Flag enum

查看:132
本文介绍了表示Flag枚举中的所有值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在python Flags枚举中包含一个 ALL标志,

I would like to have a "ALL" flag in my python Flags enum for which

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

因为这个枚举可能在任何发展状态下都会增长,所以我希望拥有类似的东西

Because this enum might grow at any state of development I would like to have something like

@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'

$ b不支持的操作数类型
$ b

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

Please note that this question currently only relates to python 3.6 or later.

推荐答案

有解决此问题的几种方法:

There are a few ways to overcome this issue:

使用类修饰符(请参见 MSeifert的答案

use a class decorator (see MSeifert's answer)

使用mixin( 当前越野车

use a mixin (currently buggy)

创建一个新的基类(见下文)

create a new base class (see below)

使用class属性方法要注意的一件事是,因为描述符是在类,而不是元类,通常可以防止设置和删除ng不存在-换句话说:

One thing to be aware of with the class property method is since the descriptor is defined on the class and not the metaclass the usual protections against setting and deleting are absent -- in other words:

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

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






创建一个新的基类:


Creating a new base class:

# 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 _ 中设置名称-允许为枚举成员提供相同的保护:

The interesting difference in the ALL property is the setting of the name in _member_map_ -- this allows the same protections afforded to Enum members:

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

但是,这里有一个竞争条件:if RefreshFlag.ALL =。 .. 之前 RefreshFlag发生。ALL第一次被激活,然后被破坏;因此,在这种情况下,我将使用装饰器,因为装饰器将在处理Enum之前对其进行处理。

However, there is a race condition here: if RefreshFlag.ALL = ... occurs before RefreshFlag.ALL is activated the first time then it is clobbered; for this reason I would use a decorator in this instance, as the decorator will process the Enum before it can be clobbered.

# 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>

这篇关于表示Flag枚举中的所有值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆