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

如何为递归转换SpecialDict至标准dict的函数添加正确Python类型注解?

问题:为递归转换SpecialDict的函数添加正确类型注解

我正在处理一个数据库返回的SpecialDict对象(dict的子类),它无法接收类型参数,需要转换为标准dict。我写了递归函数converter处理嵌套的SpecialDict,容器约束如下:

  • 键始终为str
  • 可包含其他SpecialDict实例
  • 可包含list
  • 最终叶子节点为int或str原子值

递归实现代码如下:

SUPPORTED_CONTAINER_TYPES = (dict, list)
SUPPORTED_ATOMIC_TYPES = (str, int)


class SpecialDict(dict):
    pass


def converter(container):
    if isinstance(container, dict):
        dict_ = {}
        for key, value in container.items():
            if isinstance(value, SUPPORTED_CONTAINER_TYPES):
                dict_[key] = converter(container=value)
            elif isinstance(value, SUPPORTED_ATOMIC_TYPES):
                dict_[key] = value
            else:
                raise TypeError(f"{type(value)} is not supported.")

        return dict_

    if isinstance(container, list):
        datastore_list = []
        for item in container:
            if isinstance(item, SUPPORTED_CONTAINER_TYPES):
                datastore_list.append(converter(container=item))
            elif isinstance(item, SUPPORTED_ATOMIC_TYPES):
                datastore_list.append(item)
            else:
                raise TypeError(f"{type(item)} is not supported.")

        return datastore_list

    raise TypeError(f"{type(container)} is not supported.")

尝试添加递归类型注解时遇到多个mypy错误,无法准确表达嵌套结构的类型约束,求正确的函数类型注解方案。


解决方案

要正确标注这种递归嵌套的结构,需要使用递归类型定义,结合TypeVar和Union来描述允许的嵌套层级。以下是修改后的带类型注解的代码:

from typing import TypeVar, Union, Dict, List

# 启用字符串形式的类型引用,解决递归类型的循环引用问题(Python 3.7+需要)
from __future__ import annotations


SUPPORTED_CONTAINER_TYPES = (dict, list)
SUPPORTED_ATOMIC_TYPES = (str, int)


class SpecialDict(dict):
    pass


# 定义递归类型变量:T可以是原子类型,或者嵌套的字典/列表
T = TypeVar('T', bound=Union[str, int, 'NestedDict', 'NestedList'])
# 嵌套字典:字符串键对应递归类型T
NestedDict = Dict[str, T]
# 嵌套列表:元素是递归类型T
NestedList = List[T]


def converter(container: Union[SpecialDict, NestedList]) -> Union[NestedDict, NestedList]:
    if isinstance(container, dict):
        dict_: NestedDict = {}
        for key, value in container.items():
            if isinstance(value, SUPPORTED_CONTAINER_TYPES):
                dict_[key] = converter(container=value)
            elif isinstance(value, SUPPORTED_ATOMIC_TYPES):
                dict_[key] = value
            else:
                raise TypeError(f"{type(value)} is not supported.")

        return dict_

    if isinstance(container, list):
        datastore_list: NestedList = []
        for item in container:
            if isinstance(item, SUPPORTED_CONTAINER_TYPES):
                datastore_list.append(converter(container=item))
            elif isinstance(item, SUPPORTED_ATOMIC_TYPES):
                datastore_list.append(item)
            else:
                raise TypeError(f"{type(item)} is not supported.")

        return datastore_list

    raise TypeError(f"{type(container)} is not supported.")

注解说明

  1. 递归类型定义:通过TypeVar绑定Union[str, int, 'NestedDict', 'NestedList'],让类型系统能识别嵌套的字典和列表结构。
  2. 字符串类型引用:使用'NestedDict'和'NestedList'的字符串形式,配合from __future__ import annotations避免递归类型的循环引用报错。
  3. 函数注解:参数container允许接收SpecialDict或嵌套列表,返回值对应转换后的标准嵌套字典或列表,mypy可以正确推断每一层的类型。

如果使用Python 3.10+,可以用PEP 604的|语法简化类型定义:

# Python 3.10+ 简化写法
T = TypeVar('T', bound=str | int | 'NestedDict' | 'NestedList')
NestedDict = Dict[str, T]
NestedList = List[T]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:52:42