让我们假设我们需要一个接受任何类型的两个参数的函数,只要这两个参数具有相同的类型。您将如何使用 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
Run Code Online (Sandbox Code Playgroud)
对于此代码,mypy 可以确保 to 的参数f是两个ints 或两个strs 或两个ints列表或两个返回 的零参数函数int。
但是如果我们事先不知道类型怎么办?如果我们需要类似于let f (a:'t) (b:'t) = ()F# 和 OCaml 的东西怎么办?简单地写作T = TypeVar('T')会使事情变得f(1, "2")有效,这不是我们想要的。
您要求的是不可能的(请参阅下面的解释)。但通常情况下,Python 中不需要要求两个参数具有完全相同的类型。
在您的示例中,int, str, List[int],Callable[[], int]没有任何通用方法或属性(除了任何两个object实例所具有的),因此除非您使用 手动检查类型isinstance,否则您实际上无法对您的参数执行任何您无法执行的操作与实例一起做object。您能解释一下您的用例吗?
Mypy 类型系统具有子类型。因此,当您编写时f(a, b), mypy 仅检查 的类型a和b都是 的子类型,T而不是精确等于T。
此外, mypy 子类型系统大多是预定义的,不受程序员控制,特别是每个类型都是object. (IIUC,在 OCaml 中,程序员需要明确说明哪些类型应该处于子类型关系中,因此默认情况下每个类型约束都是相等约束。这就是为什么您可以在 OCaml 中执行您想要的操作)。
所以,当你写
T = TypeVar('T')
f(a: T, b: T) -> None: ...
f(x, y)
Run Code Online (Sandbox Code Playgroud)
您只是告诉 mypy 的类型x和y必须是某种常见类型的子类型T。当然,这个约束总是(简单地)通过推断T是 来满足object。
更新
对于评论中的问题(是否可以确保 type 是 typey的子类型x?),答案也是否定的。
尽管mypy允许类型变量由指定类型从上面限制,但该限制不能是另一个类型变量,因此这不起作用:
T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
953 次 |
| 最近记录: |