You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以Pythonic方式在仅含Getter方法的类中使用match/case语句?

问题描述

我使用一些非自研的类,这些类仅提供Getter方法(如a()、b())而非属性/特性来访问内部数据。例如有如下类定义:

class Foo:
    def __init__(self, a, b) -> None:
        self._a = a
        self._b = b

    def a(self): return self._a
    def b(self): return self._b
    def c(self): return self._a + self._b

我尝试用Python的match/case语法实现如下逻辑,但代码无法运行——因为case语句匹配对象时,要求命名参数对应类的属性/特性,而非Getter方法:

foo_list = [
    Foo(1,0),
    Foo(0,1),
    Foo(1,2),
    Foo(3,3),
    Foo(3,2),
]

for foo in foo_list:
    match foo:
        case Foo(a=a, b=0):
            print(f'first a = {a}, b = {foo.b}')
        case Foo(a=0, b=b):
            print(f'second a = {foo.a}, b = {b}')
        case Foo(a=1, b=b):
            print(f'third a = {foo.a}, b = {b}')
        case Foo(a=a, b=3):
            print(f'forth a = {a}, b = {foo.b}')
        case Foo(a=a, b=b, c=5):
            print(f'fifth a = {a}, b = {b}, c = {foo.c}')

请问如何以Pythonic的方式解决这个问题?


解决方案

方法1:使用守卫条件(Guard Clauses)

这是最直接的方案,无需额外封装,直接在case后添加if条件调用Getter方法,完全贴合原逻辑的匹配优先级:

for foo in foo_list:
    match foo:
        case _ if foo.a() == 1 and foo.b() == 0:
            print(f'first a = {foo.a()}, b = {foo.b()}')
        case _ if foo.a() == 0:
            b_val = foo.b()
            print(f'second a = {foo.a()}, b = {b_val}')
        case _ if foo.a() == 1:
            b_val = foo.b()
            print(f'third a = {foo.a()}, b = {b_val}')
        case _ if foo.b() == 3:
            a_val = foo.a()
            print(f'forth a = {a_val}, b = {foo.b()}')
        case _ if foo.c() == 5:
            a_val = foo.a()
            b_val = foo.b()
            print(f'fifth a = {a_val}, b = {b_val}, c = {foo.c()}')

方法2:编写专属适配类

如果需要多次对这类对象使用match/case,可以封装一个适配器,将Getter方法转为只读属性,保留match/case的结构化匹配语法:

class FooAdapter:
    def __init__(self, foo_obj):
        self._foo = foo_obj

    @property
    def a(self):
        return self._foo.a()

    @property
    def b(self):
        return self._foo.b()

    @property
    def c(self):
        return self._foo.c()

# 使用时先包装原对象
for foo in foo_list:
    adapted = FooAdapter(foo)
    match adapted:
        case FooAdapter(a=a, b=0):
            print(f'first a = {a}, b = {adapted.b}')
        case FooAdapter(a=0, b=b):
            print(f'second a = {adapted.a}, b = {b}')
        case FooAdapter(a=1, b=b):
            print(f'third a = {adapted.a}, b = {b}')
        case FooAdapter(a=a, b=3):
            print(f'forth a = {a}, b = {adapted.b}')
        case FooAdapter(a=a, b=b, c=5):
            print(f'fifth a = {a}, b = {b}, c = {adapted.c}')

方法3:通用Getter适配器

如果需要适配多个类似的Getter风格类,可以写一个通用适配器,通过__getattr__动态将方法调用转为属性访问:

class GetterAdapter:
    def __init__(self, obj):
        self._obj = obj

    def __getattr__(self, name):
        # 尝试调用对应名称的Getter方法
        try:
            getter = getattr(self._obj, name)
            return getter()
        except AttributeError:
            raise AttributeError(f"'{type(self._obj).__name__}' object has no attribute '{name}'")

# 适配任意Getter风格的类
for foo in foo_list:
    adapted = GetterAdapter(foo)
    match adapted:
        case GetterAdapter(a=a, b=0):
            print(f'first a = {a}, b = {adapted.b}')
        case GetterAdapter(a=0, b=b):
            print(f'second a = {adapted.a}, b = {b}')
        case GetterAdapter(a=1, b=b):
            print(f'third a = {adapted.a}, b = {b}')
        case GetterAdapter(a=a, b=3):
            print(f'forth a = {a}, b = {adapted.b}')
        case GetterAdapter(a=a, b=b, c=5):
            print(f'fifth a = {a}, b = {b}, c = {adapted.c}')

内容的提问来源于stack exchange,提问作者nPn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:22:20