typings 模块中的重载装饰器似乎没有按预期运行
Overload decorator in typings module doesn't seem to behave as expected
>>> from typing import overload
>>> @overload
... def hello(s: int):
... return "Got an integer!"
>>> def hello(s: str):
... return "Got a string"
为什么调用 hello(1)
调用带有字符串参数的函数?理想情况下,@overload
运算符应该处理它,对吗?
不幸的是,python 不允许函数重载。每次你认为你在重载函数时,你只是在覆盖以前的函数声明。引自 docs:
The @overload decorator allows describing functions and methods that
support multiple different combinations of argument types. A series of
@overload-decorated definitions must be followed by exactly one
non-@overload-decorated definition (for the same function/method). The
@overload-decorated definitions are for the benefit of the type
checker only, since they will be overwritten by the
non-@overload-decorated definition, while the latter is used at
runtime but should be ignored by a type checker. At runtime, calling a
@overload-decorated function directly will raise 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)
更改为 return 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'
请注意,实际实现仍然 returns str
- python 不会在此处执行任何检查。但是,PyCharm 会发出警告:
mypy
也抱怨无效类型:
➜ mypy test.py
test.py:25: error: Unsupported operand types for + ("int" and "str")
typing
模块的目的是允许第三方工具对您的代码执行静态检查。这里没有魔法——所有类型在运行时都会被忽略。
# 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>
小绿斑
小红护卫舰
>>> from typing import overload
>>> @overload
... def hello(s: int):
... return "Got an integer!"
>>> def hello(s: str):
... return "Got a string"
为什么调用 hello(1)
调用带有字符串参数的函数?理想情况下,@overload
运算符应该处理它,对吗?
不幸的是,python 不允许函数重载。每次你认为你在重载函数时,你只是在覆盖以前的函数声明。引自 docs:
The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method). The @overload-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-@overload-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a @overload-decorated function directly will raise 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)
更改为 return 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'
请注意,实际实现仍然 returns str
- python 不会在此处执行任何检查。但是,PyCharm 会发出警告:
mypy
也抱怨无效类型:
➜ mypy test.py
test.py:25: error: Unsupported operand types for + ("int" and "str")
typing
模块的目的是允许第三方工具对您的代码执行静态检查。这里没有魔法——所有类型在运行时都会被忽略。
# 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>
小绿斑
小红护卫舰