为何fractions.Fraction不支持位置子模式?Python模式匹配疑问
核心规则说明
- 你看到的第一段
list匹配代码可运行,并非list支持通用的多位置子模式匹配,而是Python对内置序列类型做了特殊适配:list、tuple、str、bytes、bytearray、array.array、collections.deque、memoryview这几个内置序列类型,在作为类模式的匹配类时,仅支持传入恰好1个位置子模式,这个子模式会按序列匹配规则校验整个容器的内容。你写的case list((1,2,3))本质等价于序列模式case [1,2,3],括号内的(1,2,3)是单个序列模式,不是三个独立的位置子参数。如果尝试写case list(1,2,3)传入3个位置子模式,会抛出和Fraction示例完全相同的错误。 - 除了上述内置序列的特殊规则外,其余所有类型(含自定义类、标准库其他类)是否支持位置子模式,唯一判断标准是类是否定义了
__match_args__类属性。这个属性是一个字符串元组,按顺序声明了每个位置子模式对应的实例属性名。比如标准库dataclass会根据类定义的字段顺序自动生成__match_args__,因此dataclass类型可以直接使用位置子模式匹配。 fractions.Fraction没有定义__match_args__,因此默认不接受任何位置子模式,传入2个位置参数时自然会抛出TypeError。
设计原因
标准库没有为Fraction这类类型添加__match_args__是刻意的设计决策,并非遗漏:
__match_args__属于类的公开API契约,一旦发布就相当于永久承诺位置子模式对应的属性、顺序不会变更,后续版本如果调整会直接破坏所有依赖位置匹配的业务代码。- 对于Fraction这类数值类型,核心开发团队认为没有必要为了模式匹配的位置写法,额外锁死构造参数与实例属性的对应关系、公开属性名的稳定性,避免给后续版本迭代增加不必要的约束。
- 即使没有
__match_args__,依然可以通过关键字子模式完成属性匹配,这种写法不依赖参数顺序,可读性和稳定性更好:
from fractions import Fraction frctn = Fraction(1, 2) match frctn: case Fraction(numerator=1, denominator=2): print(1) # 可正常运行输出1
如果确实需要使用位置写法匹配Fraction,手动为其添加__match_args__声明即可生效:
from fractions import Fraction Fraction.__match_args__ = ("numerator", "denominator") frctn = Fraction(1, 2) match frctn: case Fraction(1, 2): print(1) # 正常输出1
内容的提问来源于stack exchange,提问作者apostofes
相关产品推荐
相关产品推荐

