首页 > 解决方案 > 类型模块中的重载装饰器似乎没有按预期运行

问题描述

>>> from typing import overload

>>> @overload
... def hello(s: int):
...     return "Got an integer!"

>>> def hello(s: str):
...     return "Got a string"

为什么调用hello(1)调用带有字符串参数的函数?理想情况下,@overload操作员应该处理它,对吗?

标签: pythonpython-3.xoverloadingstrong-typing

解决方案


不幸的是,python 不允许函数重载。每次你认为你正在重载函数时,你只是在覆盖之前的函数声明。从文档中引用:

@overload 装饰器允许描述支持多种不同参数类型组合的函数和方法。一系列@overload-decorated 定义必须紧跟一个非@overload-decorated 定义(对于相同的函数/方法)。@overload-decorated 定义仅用于类型检查器,因为它们将被非@overload-decorated 定义覆盖,而后者在运行时使用但应被类型检查器忽略。在运行时,直接调用 @overload-decorated 函数将引发 NotImplementedError。

的正确用法typing.overload如下:

from typing import overload


@overload
def hello(s: int) -> str:
    ...


@overload
def hello(s: str) -> str:
    ...


def hello(s):
    if isinstance(s, int):
        return "Got an integer!"
    if isinstance(s, str):
        return "Got a string"
    raise ValueError('You must pass either int or str')


if __name__ == '__main__':
    print(hello(1))

为了显示typing.overload让我们更改def hello(s: int)为 returnint而不是的实际好处str

from typing import overload


@overload
def hello(s: int) -> int:
    ...


@overload
def hello(s: str) -> str:
    ...


def hello(s):
    if isinstance(s, int):
        return "Got an integer!"
    if isinstance(s, str):
        return "Got a string"
    raise ValueError('You must pass either int or str')


if __name__ == '__main__':
    print(hello(1))
    a = hello(1) + 1
    b = hello(1) + 'a'

请注意,实际实现仍然返回str- python 在这里不执行任何检查。然而,PyCharm 提出了一个警告:

在此处输入图像描述

mypy还抱怨无效类型:

➜ mypy test.py 
test.py:25: error: Unsupported operand types for + ("int" and "str")

模块的目的typing是允许第三方工具对您的代码执行静态检查。这里没有魔法——所有类型在运行时都会被忽略。


推荐阅读