在 Python 中使用 Flags 时,模式匹配仅捕获直接相等而不是包含。但是,如果您认为这是一种特殊情况,则可以通过条件和
in
来规避它,前提是您之前捕获了 0
标志:
from enum import Flag
class Test(Flag):
ONE = 1
TWO = 2
THREE = ONE | TWO
NONE = 0
def match_one(pattern):
match pattern:
case Test.THREE:
print(pattern, 'Three')
case Test.ONE:
print(pattern, 'ONE')
case v if v in Test.THREE:
print(pattern, 'in THREE')
case _:
print(pattern, 'Other')
测试.一对一
测试.三中二
测试.三三
测试。三个都没有
但是,在使用多个标志时,使用这样的条件是有限制的。 一个最小的示例是尝试将 OBJ_1 与 TYPE_1(ATTR_1 或 ATTR_2 或 TYPE_1)匹配,或将 OBJ_2 与 TYPE_2(ATTR_3、ATTR_4 或 TYPE_2)匹配(问题不限于如此简单的情况,但这是一个很好的最小示例)代表)
class Flag_1(Flag):
OBJ_1 = 1
OBJ_2 = 2
NONE = 0
class Flag_2(Flag):
ATTR_1 = 1
ATTR_2 = 2
ATTR_3 = 4
ATTR_4 = 8
TYPE_1 = ATTR_1 | ATTR_2
TYPE_2 = ATTR_3 | ATTR_4
NONE = 0
可以这样做
match flag1, flag2:
case Flag_1.NONE, _ | _, Flag_2.NONE:
print('Useless')
case (Flag_1.OBJ_1, c) if c in Flag_1.TYPE_1:
print('Do 1')
case (Flag_1.OBJ_2, c) if c in Flag_1.TYPE_2:
print('Do 1')
case _:
print('Other stuff')
或
match flag1, flag2:
case Flag_1.NONE, _ | _, Flag_2.NONE:
print('Useless')
case (Flag_1.OBJ_1, Flag_2.ATTR_1 | Flag_2.ATTR_2) \
| (Flag_1.OBJ_2, Flag_2.ATTR_3 | Flag_2.ATTR_4):
print('Do 1')
case _:
print('Other stuff')
然而,当存在更多组合并添加许多重复相同操作的行时,解决方案 1 是有限的。另一方面,如果
TYPE_1
包含 10 个标志,则解决方案 2 会受到限制,因为这将是一条很长的线。
像下面这样的事情是不可能通过模式匹配实现的(我认为更适合于
if
声明)
case (Flag_1.OBJ_1, c) if c in Flag_2.TYPE_1 \
| (Flag_1.OBJ_2, c) if c in Flag_2.TYPE_2: # invalid syntax
由于模式匹配的工作方式,以下内容不会像之前解释的那样工作
case (Flag_1.OBJ_1, Flag_2.TYPE_1) \
| (Flag_1.OBJ_2, Flag_2.TYPE_2) \
是否有比解决方案 1 更好的方法,即为每个组合执行一个
case
,尽管所有组合都具有相同的结果,或者使用 if
语句来匹配组合的 Flag?
匹配大小写模式非常强大,但我认为这不是正确的解决方案。 您可以使用一些 if 语句以更容易理解的方式完成此任务。
def check_two(flag1: Flag_1, flag_2: Flag_2):
if not (flag1 or flag2):
return 'Useless'
if (flag1 & Flag_1.OBJ_1) and (flag2 & Flag_2.TYPE_1):
return 'Obj-1, Type-1'
if (flag1 & Flag_1.OBJ_2) and (flag2 & Flag_2.TYPE_2):
return 'Obj-2, Type-2'
return 'Other mix'