Python 中的模式匹配以捕获枚举标志组合

问题描述 投票:0回答:1

在 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?

python pattern-matching enum-flags
1个回答
0
投票

匹配大小写模式非常强大,但我认为这不是正确的解决方案。 您可以使用一些 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'
© www.soinside.com 2019 - 2024. All rights reserved.