代码之家  ›  专栏  ›  技术社区  ›  Tobias Hermann

默认参数是否覆盖mypy的类型提示?

  •  3
  • Tobias Hermann  · 技术社区  · 6 年前

    以下代码被拒绝 mypy 如预期:

    def foo(value: int) -> None:
        print(value, type(value))
    foo(None)
    

    输出:

    error: Argument 1 to "foo" has incompatible type "None"; expected "int"
    

    但在引入默认参数后 None ,不再有错误:

    def foo(value: int=None) -> None:
        print(value, type(value))
    foo(None)
    

    我希望 我的孩子 只允许 (作为参数和默认值)如果我们更改 value int Optional[int] 但似乎不需要这样做。为什么?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Michael0x2a    6 年前

    使关键字参数接受时 None ,mypy将隐式地使该参数的类型为 Optional[Blah] 如果还没有。您可以通过添加 reveal_type(...) 对代码和运行的函数 mypy 以下内容:

    def foo(value: int = None) -> None:
        print(value, type(value))
    
    reveal_type(foo)
    foo(None)
    

    输出将是:

    test.py:4: error: Revealed type is 'def (value: Union[builtins.int, None] =)'
    

    (请务必删除 reveal_type 但是,在实际运行代码之前,由于函数实际上在运行时并不存在——这只是mypy用来帮助调试的特殊情况。)

    这种行为之所以存在,主要是因为它有助于降低函数签名的噪声。毕竟,如果 value 在某种程度上,可以不接受,显然它必须同时接受int和none。在这种情况下,为什么不直接推断 Optional[None] (相当于 Union[int, None] ,btw)这样用户就不需要重复相同的信息两次了?

    当然,并不是每个人都喜欢这种行为:有些人更喜欢直截了当。在这种情况下,用 --no-implicit-optional 标志。将产生以下输出:

    test.py:1: error: Incompatible default for argument "value" (default has type "None", argument has type "int")
    test.py:4: error: Revealed type is 'def (value: builtins.int =)'
    test.py:5: error: Argument 1 to "foo" has incompatible type "None"; expected "int"
    

    当然,您需要更改函数签名。

    如果你想以其他方式提高Mypy的严格性,试着通过 --strict 标志。将自动启用 --无隐式可选 以及其他一些严格的标志。有关详细信息,请运行 mypy --help .