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

Tob*_*ann 7 python default-parameters nonetype mypy python-typing

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

def foo(value: int) -> None:
    print(value, type(value))
foo(None)
Run Code Online (Sandbox Code Playgroud)

输出:

error: Argument 1 to "foo" has incompatible type "None"; expected "int"
Run Code Online (Sandbox Code Playgroud)

但是在引入了一个默认参数之后None,就没有错误了:

def foo(value: int=None) -> None:
    print(value, type(value))
foo(None)
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*x2a 10

当您让关键字参数接受时None,mypy 将隐式地使该参数成为类型(Optional[Blah]如果它还没有)。您可以通过将reveal_type(...)函数添加到代码中并运行来亲眼看到这一点mypy

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

reveal_type(foo)
foo(None)
Run Code Online (Sandbox Code Playgroud)

输出将是:

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

(请务必reveal_type在实际运行代码之前删除,因为该函数在运行时实际上并不存在——它只是 mypy 的特殊情况以帮助调试。)

这种行为之所以存在,主要是因为它有助于降低函数签名的噪音。毕竟,如果value在某些时候允许为 None,显然它必须同时接受整数和 None。在这种情况下,为什么不只是推断类型Optional[None](相当于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"
Run Code Online (Sandbox Code Playgroud)

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

如果您想以其他各种方式提高 mypy 的严格性,请尝试传入--strict标志。这将自动启用--no-implicit-optional和其他几个严格标志。有关更多详细信息,请运行mypy --help


bad*_*der 5

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

联合类型 - PEP 484

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

def handle_employee(e: Employee = None): ...
Run Code Online (Sandbox Code Playgroud)

这将被视为等同于:

def handle_employee(e: Optional[Employee] = None) -> None: ...
Run Code Online (Sandbox Code Playgroud)

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

如果我们查看PEP 484 的修订历史记录,我们会发现“GitHub 的指责”,这反过来又在Pull request #689中给出了其推理,并引用了打字问题 #275