类型提示接受多个类型的序列的函数

问题描述 投票:0回答:1

我正在尝试为接受序列的函数提供类型提示包含两个type元素之一,而我不知如何使mypy变得快乐。请注意,序列是同质的,这意味着类型不能混合,要么是非,要么是。通常,当它们是“兼容”类型时,例如路径strpathlib.Path对象,并使用Union进行注释就可以了。但是在序列的情况下,Sequence[Union[..]](或Union[Sequence[..]])似乎不起作用。这是一个最小的工作示例:

from pathlib import Path
from typing import Sequence, Dict, Union


def fn_accepts_dict(adict):
    """Function from an external module that accepts `dict`s."""
    for key, val in adict.items():
        print(f"{key}, {val}")


def vararg_test(resources: Sequence[Union[str, Dict]]):
    """My function where I want to provide type hints"""
    if isinstance(resources[0], str):
        resources2 = [{"path": Path(f)} for f in resources]
    else:
        resources2 = resources
    for d in resources2:
        fn_accepts_dict(d)

现在,使用上述定义,使用以下任一方法调用vararg_test这两个工作按预期进行:

l1 = ["foo/bar", "bar/baz"]
l2 = [{"path": Path("foo/bar")}, {"path": Path("bar/baz")}]

但是运行mypy给我以下错误:

type_hints.py:14: error: Argument 1 to "Path" has incompatible type "Union[str, Dict[Any, Any]]"; expected "Union[str, _PathLike[str]]"
type_hints.py:16: error: Incompatible types in assignment (expression has type "Sequence[Union[str, Dict[Any, Any]]]", variable has type "List[Dict[str, Path]]")
Found 2 errors in 1 file (checked 1 source file)

我该如何解决?

编辑:为了提供一些背景信息,str是一个路径,dict具有与该路径相对应的元数据,并且函数fn_accepts_dict将元数据整理为一个元数据对象。因此,它们的逻辑流程为:str -> dict -> fn_accepts_dictdict -> fn_accepts_dict

虽然@ShadowRanger的建议看起来很有希望,但没有运气。我收到以下提示同样的错误:

def vararg_test2(resources: Union[Sequence[str], Sequence[Dict]]):
    ... # same implementation as above

mypy错误:

type_hints.py:24: error: Argument 1 to "Path" has incompatible type "Union[str, Dict[Any, Any]]"; expected "Union[str, _PathLike[str]]"
type_hints.py:26: error: Incompatible types in assignment (expression has type "Union[Sequence[str], Sequence[Dict[Any, Any]]]", variable has type "List[Dict[str, Path]]")
python python-3.x type-hinting mypy
1个回答
0
投票

我建议not根据参数的类型,尝试在一个函数中做两种不同的事情。而是定义两个不同的函数,每个函数采用一种特定的序列类型。

def do_with_strings(resources: Sequence[str]):
    do_with_dicts([{"path": Path(f)} for f in resources])


def do_with_dicts(resources: Sequence[dict]):
    for d in resources:
        fn_accepts_dict(d)

对于您编写的代码,resources的类型必须为ShadowRanger在注释中建议的Union[Sequence[str],Sequence[dict]],因为您假设整个列表的类型与第一个元素相同。

如果要保留异构类型,则需要检查每个元素以确定需要将其转换为dict

def vararg_test(resources: Sequence[Union[str, Dict]]):
    for f in resources:
        if isinstance(f, str):
            f = {"path": Path(f)}
        fn_accepts_dict(f)
© www.soinside.com 2019 - 2024. All rights reserved.