我正在尝试完美地键入注释以下 Python 函数:
from typing import Callable, Any
import inspect
def foo(func: Callable[..., Any]) -> None:
if inspect.isclass(func):
raise ValueError
# Do something...
class Bad:
pass
def good() -> Bad:
return Bad()
foo(good) # OK
foo(Bad) # NOK
我想缩小
Callable[..., Any]
类型的范围,以便它拒绝作为参数传递的 Bad
。
请参阅 Mypy 游乐场此处。
typing
模块和 Mypy 文档中找不到任何东西来区分简单函数和类。这可能吗?
不清楚为什么
type(Bad)
和 type(good)
在运行时非常不同,但我找不到类型注释的等效项。
如您所知,
Callable
是一种结构类型,因此任何具有__call__
实例方法的东西(包括所有类,因为类是type
的实例,并且type.__call__
) 允许您使用调用语法 Bad()
) 将满足 Callable
.
Python 类型系统不完全支持静态键入某些内容以对类型的子集进行不同的行为;例如,如果您尝试输入“”整数而不是“
0
””,您也会遇到同样的问题。最接近的是用 @typing.overload
创建 typing.Never
,这表示 foo
在运行时会出错,无论如何,这就是你对 foo
的实现。在这里,mypy 将在调用站点预计在运行时失败后的第一行抛出错误(示例在 mypy-playground 中给出,复制如下):
from typing_extensions import Callable, Any, overload, Never
import inspect
@overload
def foo(func: type) -> Never: ...
@overload
def foo(func: Callable[..., Any]) -> None: ...
def foo(func: Callable[..., Any]) -> None:
if inspect.isclass(func):
raise ValueError
# Do something...
class Bad:
pass
def good() -> Bad:
return Bad()
foo(good) # OK
foo(Bad) # NOK
a = 3 # mypy: Statement is unreachable [unreachable]
这需要指定
--warn-unreachable
CLI 选项或 warn_unreachable = True
配置文件选项才能工作。