有没有办法将表示多个标志成员的字符串转换为复合 enum.Flag?
Is there a way to convert a string representing multiple flag members to a composite enum.Flag?
我观察到我可以将某些整数值转换为它们的标志分解类型,并且我可以将标志字符串名称转换为标志,但我还没有想出是否有办法转换字符串联合标志名称到 enum.Flag
.
import enum
flag = enum.Flag('flg' , ['a', 'b', 'c', 'd'] )
# Valid 1:1 conversions...
>>> flag["a"]
<flg.a: 1>
>>> flag["b"]
<flg.b: 2>
>>> flag(1)
<flg.a: 1>
>>> flag(2)
<flg.b: 2>
# Valid union int conversion
>>> flag(7)
<flg.c|b|a: 7>
>>> flag(15) # largest integer flag can represent (1+2+4+8)
<flg.d|c|b|a: 15>
# Out of bounds
>>> flag(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Anaconda3\lib\enum.py", line 291, in __call__
return cls.__new__(cls, value)
File "C:\Anaconda3\lib\enum.py", line 533, in __new__
return cls._missing_(value)
File "C:\Anaconda3\lib\enum.py", line 673, in _missing_
possible_member = cls._create_pseudo_member_(value)
File "C:\Anaconda3\lib\enum.py", line 688, in _create_pseudo_member_
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 16 is not a valid flg
我希望我能够本着
flag["d|c|b|a"]
,但作为字典,此转换仅适用于不同的标志成员名称,不适用于它们的任何聚合。与此同时,我正在手动进行拆分、转换、联合合并,但我很好奇是否有像 int 转换案例那样更直接的途径。
编辑:
查看 enum.py 的来源,似乎正确的术语不是 union,而是 composite
# enum.py
def _create_pseudo_member_(cls, value):
"""
Create a composite member iff value contains only members.
"""
您可以子类化 enum.Flag
并拦截它的 _missing_()
方法:
from functools import reduce
import enum
class UnionFlag(enum.Flag):
@classmethod
def _missing_(cls, value):
if isinstance(value, str):
return reduce(cls.__or__, (cls[s] for s in value.split('|')))
else:
return super()._missing_(value)
>>> flag = UnionFlag('uflg', ['a', 'b', 'c', 'd'])
>>> flag.a
<uflg.a: 1>
>>> flag(3)
<uflg.b|a: 3>
>>> flag['c']
<uflg.c: 4>
>>> flag('a|b|d')
<uflg.d|b|a: 11>
我观察到我可以将某些整数值转换为它们的标志分解类型,并且我可以将标志字符串名称转换为标志,但我还没有想出是否有办法转换字符串联合标志名称到 enum.Flag
.
import enum
flag = enum.Flag('flg' , ['a', 'b', 'c', 'd'] )
# Valid 1:1 conversions...
>>> flag["a"]
<flg.a: 1>
>>> flag["b"]
<flg.b: 2>
>>> flag(1)
<flg.a: 1>
>>> flag(2)
<flg.b: 2>
# Valid union int conversion
>>> flag(7)
<flg.c|b|a: 7>
>>> flag(15) # largest integer flag can represent (1+2+4+8)
<flg.d|c|b|a: 15>
# Out of bounds
>>> flag(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Anaconda3\lib\enum.py", line 291, in __call__
return cls.__new__(cls, value)
File "C:\Anaconda3\lib\enum.py", line 533, in __new__
return cls._missing_(value)
File "C:\Anaconda3\lib\enum.py", line 673, in _missing_
possible_member = cls._create_pseudo_member_(value)
File "C:\Anaconda3\lib\enum.py", line 688, in _create_pseudo_member_
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 16 is not a valid flg
我希望我能够本着
flag["d|c|b|a"]
,但作为字典,此转换仅适用于不同的标志成员名称,不适用于它们的任何聚合。与此同时,我正在手动进行拆分、转换、联合合并,但我很好奇是否有像 int 转换案例那样更直接的途径。
编辑: 查看 enum.py 的来源,似乎正确的术语不是 union,而是 composite
# enum.py
def _create_pseudo_member_(cls, value):
"""
Create a composite member iff value contains only members.
"""
您可以子类化 enum.Flag
并拦截它的 _missing_()
方法:
from functools import reduce
import enum
class UnionFlag(enum.Flag):
@classmethod
def _missing_(cls, value):
if isinstance(value, str):
return reduce(cls.__or__, (cls[s] for s in value.split('|')))
else:
return super()._missing_(value)
>>> flag = UnionFlag('uflg', ['a', 'b', 'c', 'd'])
>>> flag.a
<uflg.a: 1>
>>> flag(3)
<uflg.b|a: 3>
>>> flag['c']
<uflg.c: 4>
>>> flag('a|b|d')
<uflg.d|b|a: 11>