Sam*_*son 4 python types typing python-3.x python-typing
我一直在努力编写"varadic"参数列表类型定义.
例如,给出类型:
def foo(fn, *args):
return fn(*args)
Run Code Online (Sandbox Code Playgroud)
我能做的最好的就是使用这里的建议:
from typing import overload, Callable, TypeVar
A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')
R = TypeVar('R')
@overload
def foo(fn: Callable[[A], R], a: A) -> R: ...
@overload
def foo(fn: Callable[[A, B], R], a: A, b: B) -> R: ...
@overload
def foo(fn: Callable[[A, B, C], R], a: A, b: B, c: C) -> R: ...
def foo(fn, *args):
return fn(*args)
Run Code Online (Sandbox Code Playgroud)
这主要是做正确的事情...例如,给定:
def bar(i: int, j: int) -> None:
print(i)
Run Code Online (Sandbox Code Playgroud)
以下成功:
foo(bar, 10, 12)
Run Code Online (Sandbox Code Playgroud)
虽然这些失败了:
foo(bar, 10)
foo(bar, 10, 'a')
foo(bar, 10, 12) + 1
Run Code Online (Sandbox Code Playgroud)
但如果我检查,mypy --strict我得到:
test.py:15: error: Function is missing a type annotation
Run Code Online (Sandbox Code Playgroud)
(这就是说最终foo定义本身没有任何类型)
我可以重新定义foo为:
def foo(fn: Callable[..., R], *args: Any) -> R:
return fn(*args)
Run Code Online (Sandbox Code Playgroud)
但是当我跑步时,mypy --strict我得到:
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 1
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 2
test.py:15: error: Overloaded function implementation does not accept all possible arguments of signature 3
Run Code Online (Sandbox Code Playgroud)
我真的不明白.
如果有人可以建议一种更好的方式给这种功能类型,将不胜感激!如果我也可以这样做而不列出很多overload很好的s,那么真正的定义也会有一些"仅限关键字"的参数,这些参数最好不要每次都重复
你得到"重载函数实现不接受所有可能的参数......"错误的原因是因为你的重载实现没有正确处理看起来像这样的调用:foo(my_callable, a=3, b=4).
毕竟,根据您的过载签名,用户理论上可以明确地使用a,b,c等命名参数 - 因此,您的实现需要支持这些类型的调用.
有两种不同的方法可以解决这个问题.
第一种方法是**kwargs: Any修改并修改您的重载实现,如下所示:
def foo(fn: Callable[..., R], *args: Any, **kwargs: Any) -> Any:
return fn(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
现在您的实现将正确处理这些类型的调用.
第二种方法是为每个参数添加两个下划线,如下所示:
@overload
def foo(fn: Callable[[A], R], __a: A) -> R: ...
@overload
def foo(fn: Callable[[A, B], R], __a: A, __b: B) -> R: ...
@overload
def foo(fn: Callable[[A, B, C], R], __a: A, __b: B, __c: C) -> R: ...
def foo(fn: Callable[..., R], *args: Any) -> Any:
return fn(*args)
Run Code Online (Sandbox Code Playgroud)
当mypy看到以两个下划线开头的参数时,它理解该参数仅仅是位置的.所以,mypy会拒绝像这样的电话foo(my_fn, __a=3, __b=4).
这是一个打字的东西.使用两个下划线为参数添加前缀在运行时没有特殊含义.
关于你不必重复这么多重载的更广泛的问题:不幸的是,在一堆重载上加上我们现在能做的最好.您正在使用的技术是使用typeshed键入类似功能相同的技术map(...)和filter(...),例如.
为了做得更好,我们需要一个名为variadic泛型的功能- 但它们是一个复杂的功能,但遗憾的是mypy还不支持它们.希望计划在2019年晚些时候实现它们,所以你可能会淘汰重载.
| 归档时间: |
|
| 查看次数: |
146 次 |
| 最近记录: |