0

我正在编写一个对象序列化程序,但遇到类模式与预期情况不匹配的问题:

def dump_obj(x):
    match(x):
        case list():
            emit('L')
            dump_obj(len(x))
            for elem in x:
                dump_obj(elem)
        case Iterable():
            emit('I')
            dump_obj((type(x), list(x)))
        case tuple():
            emit('T')
            dump_obj(list(x))
        case str():
            emit('S')
            dump_obj(len(x))
            emit(x)
        case int():
            emit('D')
            emit(str(x))
        case _:
            raise TypeError(f'Unknown obj {x!r}')

当我用一个元组调用dump_obj()时,它会在 I-case 上为 iterables 提供无限递归,而不是匹配 T-case 的元组。

当我用列表子类调用dump_obj()时,它匹配列表的 L-case 而不是 iterables 的预期 I-case。

4

1 回答 1

0

第一个问题:订购

这些案件不是相互独立的。它们从上到下进行测试(如长 if/elif 链),第一个匹配的获胜。

在这个例子中,像listtuplestr这样的特定匹配测试需要出现在像Iterable这样更一般的匹配之前。否则,使用当前代码,元组输入 like(10, 20, 30)将匹配 I-case 而不是预期的 T-case。

第二个问题:特异性

类模式执行isinstance()检查,该检查将匹配类型和该类型的子类。要将大小写限制为完全匹配,请使用类型保护

case list() if type(x) == list:
    ...

把它们放在一起

应用这两种解决方案后,以下是新代码:

def dump_obj(x):
    match(x):
        case list() if type(x) == list:   # <-- Added guard
            emit('L')
            dump_obj(len(x))
            for elem in x:
                dump_obj(elem)
        case tuple() if type(x) == tuple: # <-- Added guard
            emit('T')
            dump_obj(list(x))
        case str() if type(x) == str:     # <-- Added guard
            emit('S')
            dump_obj(len(x))
            emit(x)
        case Iterable():                  # <-- Move after list, tuple, str
            emit('I')
            dump_obj((type(x).__name__, list(x)))
        case int():
            emit('D')
            emit(str(x))
        case _:
            raise TypeError(f'Unknown obj {x!r}')

样品运行

在这里,我们展示了两个有问题的案例按预期工作。

>>> dump_obj((10, 20))     # Tuple of integers
T
L
D
2
D
10
D
20

>>> class List(list):
...     pass
...
>>> dump_obj(List((30, 40)))   # List subclass
I
T
L
D
2
S
D
4
List
L
D
2
D
30
D
40
于 2022-03-01T21:25:42.780 回答