【问题标题】:How can I ensure that arguments have same type without listing the types explicitly?如何在不明确列出类型的情况下确保参数具有相同的类型?
【发布时间】:2016-10-14 00:25:48
【问题描述】:

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

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

【问题讨论】:

    标签: python type-hinting mypy python-typing


    【解决方案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
    

    【讨论】:

    • 我明白了。事实上,mypy 在这里所做的正是我要求它做的事情:在他的理解中,1 和“2”实际上属于同一类型,因为 intstr 都是 object 的子类型。有没有办法让 mypy 确保在像 f(a: T, b: S) 这样的调用中,类型 ST 的子类型?
    • 那么在 Python 的类型提示中,普通类型变量有什么用?他们告诉我们的很少。我们可以只在任何地方使用一个类型变量。
    • @Narfanar 你可以看到一些例子说明为什么TypeVar 是有用的here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多