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

如何在Python中实现支持match语句的代数数据类型单例?

模拟Kotlin密封类的Python实现方案

问题背景

在支持代数数据类型的语言(如Kotlin)中,常用密封类实现分层数据结构:

sealed class Thing {
    data class CoolThing(val coolness: Int) : Thing()
    data class OtherThing(val other: String) : Thing()
    object BoringThing : Thing()
}

尝试在Python中模拟时,写出如下代码:

from dataclasses import dataclass
from typing import Literal

@dataclass
class CoolThing:
    coolness: int

@dataclass
class OtherThing:
    other: str

BoringThing = object()

Thing = CoolThing | OtherThing | Literal[BoringThing]

但存在两个问题:

  • 大量单例对象需用Literal包裹,操作繁琐;自定义单例类后,无法让对象兼具元类与类的特性
  • match语句对单例对象的匹配不符合预期,绑定的是名称而非值

期望实现的效果:

from dataclasses import dataclass

# <Some kind of declaration of SingletonObject>

@dataclass
class CoolThing:
    coolness: int

@dataclass
class OtherThing:
    other: str

BoringThing = SingletonObject()

Thing = CoolThing | OtherThing | BoringThing

# 支持如下匹配(假设thing是Thing类型):
match thing:
    case BoringThing:
        print('This is boring')
    case OtherThing(other):
        print(f'This is {other}')
    case CoolThing(coolness):
        print(f'This is {coolness} cool')

可行解决方案

方案1:自定义可匹配的Singleton类

通过自定义单例类,让实例能在match语句中按值匹配,同时支持类型注解:

from dataclasses import dataclass
from typing import Union, TypeVar, Generic

T = TypeVar('T')

class SingletonObject(Generic[T]):
    def __init__(self, name: str):
        self.name = name
    
    def __repr__(self):
        return self.name
    
    # 让match语句能匹配值而非名称
    def __eq__(self, other):
        return isinstance(other, SingletonObject) and self.name == other.name
    
    # 支持类型检查
    def __class_getitem__(cls, item):
        return cls

# 定义单例实例
BoringThing = SingletonObject("BoringThing")
SleepyThing = SingletonObject("SleepyThing")

@dataclass
class CoolThing:
    coolness: int

@dataclass
class OtherThing:
    other: str

# 定义联合类型
Thing = Union[CoolThing, OtherThing, SingletonObject]

# 测试匹配
def test_match(thing: Thing):
    match thing:
        case BoringThing:
            print('This is boring')
        case SleepyThing:
            print('This is sleepy')
        case OtherThing(other):
            print(f'This is {other}')
        case CoolThing(coolness):
            print(f'This is {coolness} cool')

test_match(BoringThing)  # 输出: This is boring
test_match(OtherThing("test"))  # 输出: This is test

方案2:使用Enum实现单例+数据类组合

利用Enum天然的单例特性,结合数据类实现密封类效果:

from dataclasses import dataclass
from enum import Enum
from typing import Union

# 定义单例枚举
class SingletonThing(Enum):
    BORING_THING = "BoringThing"
    SLEEPY_THING = "SleepyThing"

    def __repr__(self):
        return self.value

@dataclass
class CoolThing:
    coolness: int

@dataclass
class OtherThing:
    other: str

# 定义联合类型
Thing = Union[CoolThing, OtherThing, SingletonThing]

# 测试匹配
def test_match(thing: Thing):
    match thing:
        case SingletonThing.BORING_THING:
            print('This is boring')
        case SingletonThing.SLEEPY_THING:
            print('This is sleepy')
        case OtherThing(other):
            print(f'This is {other}')
        case CoolThing(coolness):
            print(f'This is {coolness} cool')

test_match(SingletonThing.BORING_THING)  # 输出: This is boring
test_match(CoolThing(10))  # 输出: This is 10 cool

方案3:用dataclass实现单例对象

通过dataclass(frozen=True)和__new__方法创建单例,让实例可被match语句匹配:

from dataclasses import dataclass
from typing import Union

@dataclass(frozen=True)
class SingletonObject:
    _instance = None
    name: str

    def __new__(cls, name: str):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

# 定义单例
BoringThing = SingletonObject("BoringThing")

@dataclass
class CoolThing:
    coolness: int

@dataclass
class OtherThing:
    other: str

Thing = Union[CoolThing, OtherThing, SingletonObject]

# 测试匹配
def test_match(thing: Thing):
    match thing:
        case BoringThing:
            print('This is boring')
        case OtherThing(other):
            print(f'This is {other}')
        case CoolThing(coolness):
            print(f'This is {coolness} cool')

test_match(BoringThing)  # 输出: This is boring

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:51:03