8

让我们假设我们需要一个函数,只要两个参数具有相同的类型,它就可以接受任何类型的两个参数。您将如何使用 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 可以确保 to 的参数f是两个ints 或两个strs 或两个 s 列表int或两个返回的零参数函数int

但是如果我们事先不知道类型怎么办?如果我们需要类似于let f (a:'t) (b:'t) = ()F# 和 OCaml 的东西怎么办?简单的写作T = TypeVar('T')会使事情变得f(1, "2")有效,这不是我们想要的。

4

1 回答 1

4

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

在您的示例中,int, str, List[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。当然,这个约束总是(很容易地)通过推断得到T满足object

更新

对于您在评论中的问题(是否可以确保 type ofy是 type of 的子类型x?),答案也是否定的。

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

T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None
于 2017-04-01T22:46:08.890 回答