【问题标题】:Does a default parameters overwrite type hints for mypy?默认参数是否会覆盖 mypy 的类型提示?
【发布时间】:2018-12-05 22:42:43
【问题描述】:

以下代码按预期被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)

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

【问题讨论】:

    标签: python nonetype mypy python-typing default-parameters


    【解决方案1】:

    当您让关键字参数接受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 在某些时候被允许为无,显然它必须同时接受整数和无。在这种情况下,为什么不直接将类型推断为Optional[int](相当于Union[int, None],顺便说一句),这样用户就不需要重复相同的信息两次?

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

    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 标志。这将自动启用--no-implicit-optional 和其他几个严格标志。更多详情,请运行mypy --help

    【讨论】:

    • 哇,完美的答案。非常感谢。是的,我是那种喜欢严格的类型行为的人,所以我刚刚为我们的整个代码库启用了这个标志,现在正在解决错误。 ;)
    【解决方案2】:

    为@Michael0x2a 的出色答案添加了一些具有历史深度的参考。 关于签名参数的默认值None 应使其暗示的type 隐式视为Optional[type] 的推荐推理规则最初在PEP 484 中建立,但同时发生了变化。

    Union types - PEP 484

    此 PEP 的过去版本允许类型检查器在默认值为 None 时采用可选类型,如下代码所示:

    def handle_employee(e: Employee = None): ...
    

    这将被视为等同于:

    def handle_employee(e: Optional[Employee] = None) -> None: ...
    

    这不再是推荐的行为。类型检查器应该朝着要求明确显示可选类型的方向发展。

    如果我们查看PEP 484's revision history,我们会到达"GitHub's blame",这反过来又在Pull request #689 中给出了它的推理并返回到typing issue #275

    【讨论】:

    • 谢谢!这就是我一直在寻找的答案:)
    猜你喜欢
    • 2012-01-21
    • 1970-01-01
    • 2022-01-24
    • 2019-05-09
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多