如何在不明确列出类型的情况下确保参数具有相同的类型?
How can I ensure that arguments have same type without listing the types explicitly?
让我们假设我们需要一个函数,它接受任何类型的两个参数,只要两个参数具有相同的类型即可。你如何用 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
列表或两个return int
.
的零参数函数
但是如果我们事先不知道类型怎么办?如果我们需要 F# 和 OCaml 中类似于 let f (a:'t) (b:'t) = ()
的东西怎么办?简单地写 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)
你只是在告诉 mypy x
和 y
的类型必须是某些常见类型 T
的子类型。当然,通过推断 T
是 object
.
总是(平凡地)满足这个约束
更新
对于你在评论中的问题(是否可以确保 y
类型是 x
类型的子类型?),答案也是否定的。
即使 mypy
允许类型变量由指定类型从上方绑定,该绑定不能是另一个类型变量,所以这将不起作用:
T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None
让我们假设我们需要一个函数,它接受任何类型的两个参数,只要两个参数具有相同的类型即可。你如何用 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
列表或两个return int
.
但是如果我们事先不知道类型怎么办?如果我们需要 F# 和 OCaml 中类似于 let f (a:'t) (b:'t) = ()
的东西怎么办?简单地写 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)
你只是在告诉 mypy x
和 y
的类型必须是某些常见类型 T
的子类型。当然,通过推断 T
是 object
.
更新
对于你在评论中的问题(是否可以确保 y
类型是 x
类型的子类型?),答案也是否定的。
即使 mypy
允许类型变量由指定类型从上方绑定,该绑定不能是另一个类型变量,所以这将不起作用:
T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None