类型模块中的重载装饰器似乎未达到预期的效果

时间:2018-08-27 07:43:48

标签: python python-3.x overloading strong-typing

>>> from typing import overload

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

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

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

2 个答案:

答案 0 :(得分:2)

不幸的是,python不允许函数重载。每当您认为自己正在重载函数时,您都将覆盖先前的函数声明。引用docs

  

@overload装饰器允许描述可以实现的功能和方法   支持参数类型的多种不同组合。一系列   @ 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)以返回int而不是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提出警告:

enter image description here

mypy还抱怨类型无效:

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

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

答案 1 :(得分:0)

# tested in Python 3.8.5 32-bit
# overloads the method
# imports libraries from the base distribution 
# confuses some linters
# undermines type-hinting by documenting *kwargs or dispatch signature

from functools import singledispatch

class Car:
    def __init__(self, color: str, brand: str) -> None:
        self.color = color
        self.brand = brand


@singledispatch
def describe_car(color: str, kind: str) -> str:
    return "Little " + color + " " + kind

@describe_car.register(Car)
def _(car: Car) -> str:
        return describe_car(car.color, car.brand)


newcar = Car("red", "corvette")

print(describe_car("green", "pinto"))
print(describe_car(newcar))

pythonout>
小小的绿色平托
小红色护卫舰