有几种方法可以解决此问题:
使用
classproperty
(请参阅Zero's answer
)使用类装饰器(请参阅参考资料
MSeifert's answer
)使用mixin(
currently buggy
)创建一个新的基类(见下文)
使用类属性方法要注意的一件事是,因为描述符是在类而不是元类上定义的,所以缺少针对设置和删除的常规保护措施-换句话说:
>>> RefreshFlags.ALL<RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>>>> RefreshFlags.ALL = 'oops'>>> RefreshFlags.ALL'oops'
创建一个新的基类:
# lightly testedfrom enum import Flag, autofrom operator import or_ as _or_from functools import reduceclass 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 = 9Traceback (most recent call last): ....AttributeError: Cannot reassign members.
但是,这里有一个竞争条件:如果在第一次激活 之前
RefreshFlag.ALL = ...发生 ,
RefreshFlag.ALL那么它将被破坏;因此,在这种情况下,我将使用装饰器,因为装饰器将在处理Enum之前对其进行处理。
# lightly testedfrom enum import Flag, autofrom operator import or_ as _or_from functools import reducedef 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_limitsclass RefreshFlag(Flag): EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto()>>> RefreshFlag.ALL = 99Traceback (most recent call last): ...AttributeError: Cannot reassign members.>>> RefreshFlag.ALL <RefreshFlag.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>>>> RefreshFlag.NONE<RefreshFlag.0: 0>



