Mypy:确保参数具有相同的类型,而不显式列出类型

时间:2016-10-14 00:25:48

标签: python mypy

让我们假设我们需要一个接受任何类型的两个参数的函数,只要两个参数具有相同的类型。你会如何用mypy静态检查它?

如果我们只需要函数接受一些有限数量的已知类型,那很容易:

from typing import TypeVar, List, Callable

T = TypeVar('T', int, str, List[int], Callable[[], int])

def f(a: T, b: T) -> None:
   pass

f(1, 2)
f("1", "2")
f([1], [2])
f(lambda: 1, lambda: 2)
f(1, "2") # mypy will print an error message

对于此代码,mypy可以确保f的参数是两个int或两个str或两个int列表或两个函数返回int的零参数。

但是,如果我们事先不知道这些类型怎么办?如果我们需要来自F#和OCaml的let f (a:'t) (b:'t) = ()类似的内容怎么办?只需写T = TypeVar('T')就可以使f(1, "2")之类的内容有效,而这不是我们想要的。

1 个答案:

答案 0 :(得分:1)

你所要求的是不可能的(见下面的解释)。但通常情况下,python中不需要要求两个参数具有完全相同的类型。

在您的示例中,intstrList[int]Callable[[], int]没有任何常用方法或属性(除了任何两个object之外实例有),因此,除非您使用isinstance手动检查类型,否则您无法对object个实例无法执行的参数执行任何操作。你能解释一下你的用例吗?

解释为什么不能强制执行类型相等

Mypy类型系统有子类型。因此,当您编写f(a, b)时,mypy仅会检查ab的类型是T的子类型,而不是T

此外,mypy子类型系统大多是预先定义的,不受程序员控制,特别是每种类型都是object的子类型。 (IIUC,在OCaml中程序员需要明确说出哪些类型应该在子类型关系中,所以默认情况下每个类型约束都是等式约束。这就是为什么你可以在OCaml中做你想做的事情。)

所以,当你写

T = TypeVar('T')
f(a: T, b: T) -> None: ...
f(x, y)

您只是告诉mypy xy的类型必须是某些常见类型T的子类型。当然,通过推断Tobject来总是(平凡地)满足这种约束。

更新

对于评论中的问题(是否可以确保y的类型属于x类型的子类型?),答案也是否定的。

即使mypy允许类型变量从上面被指定的类型限制,该绑定也不能是另一个类型变量,所以这不起作用:

T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None