mypy 首选“tuple[A, B|C]”还是“tuple[A,B]|tuple[A,C]”?

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

考虑以下两个注释:

def foo1(arg: tuple[datetime, int] | tuple[datetime, None]) -> datetime:
    ...

def foo2(arg: tuple[datetime, int | None]) -> datetime:
    ...

有理由使用其中一种而不是另一种吗?(除了偏好)

据我所知,它们在逻辑上是等价的;他们是吗?

python python-typing mypy
2个回答
2
投票

两者并不完全等同。

tuple[datetime, int | None]
传递给第一个变体是无效的,但对第二个变体有效。

给定

def foo1(arg: tuple[datetime, int] | tuple[datetime, None]) -> datetime:
    ...

def foo2(arg: tuple[datetime, int | None]) -> datetime:
    ...

代码

x: tuple[datetime, int | None] = ...

foo1(x)
foo2(x)

使用 mypy 进行类型检查失败并显示消息

error: Argument 1 to "foo1" has incompatible type "tuple[datetime, int | None]"; expected "tuple[datetime, int] | tuple[datetime, None]"  [arg-type]

这是否有用取决于您的用例。


1
投票

正如 Brian 在 this answer 中指出的那样,对于某种类型中的某些

C
泛型,不能保证
C[T | S]
与任何
C[T] | C[S]
T
S
兼容。

但是,这不仅会影响所有外部调用者,还会影响实现本身。考虑以下片段:

from datetime import datetime

def foo1(arg: tuple[datetime, int] | tuple[datetime, None]) -> None:
    if arg[1] is None:
        reveal_type(arg)  # N: Revealed type is "tuple[datetime.datetime, None]"
    else:
        reveal_type(arg)  # N: Revealed type is "tuple[datetime.datetime, builtins.int]"

def foo2(arg: tuple[datetime, int | None]) -> None:
    if arg[1] is None:
        reveal_type(arg)  # N: Revealed type is "tuple[datetime.datetime, Union[builtins.int, None]]"
    else:
        reveal_type(arg)  # N: Revealed type is "tuple[datetime.datetime, Union[builtins.int, None]]"

x: tuple[datetime, int | None]

foo1(x)  # E: Argument 1 to "foo1" has incompatible type "tuple[datetime, int | None]"; expected "tuple[datetime, int] | tuple[datetime, None]"  [arg-type]
foo2(x)

注意类型如何在两个函数中缩小。

在前一种情况下,您知道参数的类型为

tuple[datetime, int]
OR
tuple[datetime, None]
。因此,如果最后一项是
None
,您实际上可以将类型缩小到仅
tuple[datetime, None]
,并且它会发生。

在后者中,类型保持不变,尽管形式上这种缩小是安全的(如果我没有错过任何东西)。相同的

is None
检查不会将
tuple[datetime, int | None]
缩小为
tuple[datetime, None]
。这个实现在
mypy
pyright
中是一致的,所以在union情况下类型没有缩小可能有更深层次的原因。

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.