我想在我的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或更高版本有关。
有几种方法可以解决此问题:
使用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 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>
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句