如何在不显式列出类型的情况下确保参数具有相同的类型?

问题描述 投票:0回答:1

让我们假设我们需要一个接受任意类型的两个参数的函数,只要两个参数具有相同的类型。您将如何使用 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")
之类的东西有效,但这不是我们想要的。

python python-typing mypy
1个回答
5
投票

您所要求的是不可能的(请参阅下面的解释)。但通常情况下,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
© www.soinside.com 2019 - 2024. All rights reserved.