在嵌套字典上获取太多参数或太少参数

Getting Too many arguments or Too few arguments on nested dict

我正在尝试在 dict 类型中添加类型提示,该类型具有多个绑定函数的字段。 例如

from typing import Dict, Callable, Any, Union

def fn():
  print("Hello World")

def fn2(name):
   print("goodbye world", name)

d = {
  "hello" : {
    "world": fn
  },
  "goodbye": {
    "world": fn2
  }
} # type: Dict[str, Dict[str, Union[Callable[[], None], Callable[[str], None]]]]

d["hello"]["world"]()
d["goodbye"]["world"]("john")

我 运行 的问题是每当我尝试 运行 mypy (v0.782) 时都会抛出错误:

test2.py:17: error: Too few arguments
test2.py:18: error: Too many arguments

很明显,从函数定义和类型提示中可以看出,我传递了正确的参数。我显然遗漏了一些东西,因为它会抛出错误。

但是,以下是有效的,所以我怀疑它与 Union 输入类型提示有关。

from typing import Dict, Callable, Any, Union


def fn():
    print("Hello World")


d = {"hello": {"world": fn}}  # type: Dict[str, Dict[str, Callable[[], None]]]

d["hello"]["world"]()

提醒您,如果在使用 Union 时未考虑以下约束,就会出现问题中描述的问题:

Operations are valid for union types only if they are valid for every union item. This is why it’s often necessary to use an isinstance() check to first narrow down a union type to a non-union type. This also means that it’s recommended to avoid union types as function return types, since the caller may have to use isinstance() before doing anything interesting with the value.[1]

作为解决方法,我建议使用带有可选参数的单个函数。 我使用 Protocol 来定义带有可选参数的回调类型,使用 Callable[...]

无法表达
from typing import Protocol, Optional, Dict


class Fn(Protocol):
    def __call__(self, name: Optional[str] = None) -> None:
        ...


def fn(name: Optional[str] = None) -> None:
    if name is None:
        print("Hello World")
    else:
        print("goodbye world", name)


d: Dict[str, Dict[str, Fn]] = {
    "hello": {
        "world": fn
    },
    "goodbye": {
        "world": fn
    }
}

d["hello"]["world"]()
d["goodbye"]["world"]("john")

[1] https://mypy.readthedocs.io/en/stable/kinds_of_types.html#union-types