如何为处理递归泛型类型的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
相关产品推荐
相关产品推荐

