我正在尝试转发和/或存储
Callable
,同时提供尽可能多的类型提示。目前,我正在努力解决一个看起来很简单的 mypy
错误,但我不知何故无法解决它。想象一下这个小片段包含一组Callable
:
from collections.abc import Callable, MutableSequence
functions: MutableSequence[Callable[[int], None]] = []
def foo(val: int) -> None:
print(val)
functions.append(foo)
虽然有点无意义,但它确实有效,并且
mypy --strict
给了我零问题。
现在我想让
foo
只接受命名参数:
def foo(*, val: int) -> None:
和
mypy
给了我
./foo.py:11: error: Argument 1 to "append" of "MutableSequence" has incompatible type "Callable[[NamedArg(int, 'val')], None]"; expected "Callable[[int], None]" [arg-type]
..这听起来似乎有道理,但是有没有办法解决这个问题呢?
NamedArg
无法通过 typing
或 typing_extensions
导入,只能通过 mypy_extensions
导入,将其作为依赖项感觉很奇怪。
但即使我接受它,它也给了我一堂课,而不是一些Generic
。
如何解决这个问题而不丢失命名参数的类型提示?
顺便说一句,在现实生活中的项目中,我正在转发 kw-args,因此允许上面代码片段中的列表仅接受带有一个(通用)参数名称(如
MutableSequence[Callable[[NamedArg(int, 'val')], None]]
)的 kw-arg 就可以了。
如果
Callable[...]
语法不足以定义您的签名,您需要的是回调协议。
应用于您的示例,它看起来像这样:
from collections.abc import MutableSequence
from typing import Protocol
class FooCallable(Protocol):
def __call__(self, *, val: int) -> None:
...
functions: MutableSequence[FooCallable] = []
def foo(*, val: int) -> None:
print(val)
functions.append(foo)