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

如何为处理递归泛型类型的flatten函数编写Mypy类型签名?

如何为递归嵌套的Contains类编写flatten函数的类型签名

我定义了一个泛型类Contains,其实例仅包含一个T类型的值,且该值本身也可以是Contains对象,形成递归结构。需要编写一个flatten函数将这种递归结构展开为单个非Contains对象:

from typing import TypeVar, Generic

T = TypeVar('T')

class Contains(Generic[T]):
    val: T
    def __init__(self, val: T):
        self.val = val
def flatten(x):
    while isinstance(x, Contains):
        x = x.val
    return x

问题:flatten函数的类型签名应该如何编写?

我尝试定义递归类型Nested:

Nested = T | Contains['Nested[T]']

但类型检查器会混淆,因为T也可以是Contains对象:

def flatten(x: Nested[T]) -> T:
    while isinstance(x, Contains):
        reveal_type(x) # 显示为Contains[Unknown] | Contains[Nested]
        x = x.val
    reveal_type(x) # 显示为object* | Unknown
    return x

另一种方法是创建单独的Base类,但每次都要将参数包装在Base对象中,十分繁琐,且Base类与Contains类功能重复:

class Base(Generic[T]):
    val: T
    def __init__(self, val):
        self.val = val

Nested = Base[T] | Contains['Nested[T]']

def flatten(x: Nested[T]) -> T:
    while isinstance(x, Contains):
        x = x.val
    return x.val

有没有更简洁的实现方式?


简洁解决方案:使用递归类型别名

无需额外创建Base类,只需正确定义递归类型别名,让类型检查器识别嵌套结构即可。Python 3.10+支持TypeAlias,低版本可直接用Union:

from typing import TypeVar, Generic, TypeAlias

T = TypeVar('T')

class Contains(Generic[T]):
    val: T
    def __init__(self, val: T):
        self.val = val

# 定义递归类型:要么是最终的非嵌套类型T,要么是包含Nested[T]的Contains
Nested: TypeAlias = T | Contains['Nested[T]']

def flatten(x: Nested[T]) -> T:
    while isinstance(x, Contains):
        x = x.val
    return x

类型检查验证

对于嵌套调用,类型检查器能正确推断返回值类型:

# 示例
nested_val = Contains(Contains(42))
result = flatten(nested_val)
reveal_type(result) # 类型检查器会显示为int

原理说明

递归类型别名Nested[T]明确表示:它要么是最终的目标类型T,要么是一个包含Nested[T]的Contains对象。类型检查器会递归解析这个定义,逐步剥离Contains外层,最终确认返回值为T。如果使用mypy等类型检查器,默认已支持递归类型解析,不会出现Unknown类型的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:03:29