具有多个任意但相同类型的元组

Tuple with multiple numbers of arbitrary but equal type

目前,我正在检查具有以下形式的多个(例如三个)任意但相同类型的元组:

from typing import Tuple, Union

Union[Tuple[int, int, int], Tuple[float, float, float]]

我想让这个检查更通用,也允许 numpy 数字类型。 IE。我尝试使用 numbers.Number:

from numbers import Number
from typing import Tuple

Tuple[Number, Number, Number]

上面的片段也允许混合类型的元组,只要一切都是数字。

我想将元组限制为相同类型的数字。

如何实现?


从技术上讲,这个问题适用于 Python 和类型提示规范本身。然而,正如评论中指出的那样,它的处理是特定于实现的,即 MyPy 不会捕获每个边缘情况 and/or 不一致。就个人而言,我正在使用 运行 时间检查 typeguard 进行测试并在生产中完全停用它们。

您可以将 TypeVarbound 参数一起使用。它允许将类型限制为给定类型的子类型。在您的情况下,类型应该是 Number:

的子类型
from numbers import Number
from typing import TypeVar
 
T = TypeVar('T', bound=Number)
Tuple[T, T, T]

为什么有效?

TypeVar 是一个允许在类型签名中多次使用特定类型的变量。最简单的例子:

from typing import TypeVar, Tuple

T = TypeVar('T')
R = TypeVar('R')

def swap(x: T, y: R) -> Tuple[R, T]:
    return y, x

静态类型检查器将推断函数 swap 的参数应该与输出的顺序相同(注意 return 类型 T 将与输入类型 T 相同) .

接下来,引入对 TypeVar 的限制可能会有用。例如,可以将类型变量的值限制为特定类型:TypeVar('T', int, str)。在这个答案中,我们使用另一种带有关键字 bound 的限制——它检查类型变量的值是否是给定类型的子类型(在我们的例子中,Number,这是一个基 class 用于 Python).

中的所有数值类型

更多示例:mypy documentation and PEP 484.


工作测试:

from numbers import Number
from typing import Tuple, TypeVar

import numpy as np
from typeguard import typechecked
 
T = TypeVar('T', bound=Number)

@typechecked
def foo(data: Tuple[T, T, T]):
    print('expected OK:', data)
    
for data in (
    (1, 2, 3), # ok
    (1.0, 2.0, 3.0), # ok
    (1, 2.0, 3), # TypeError
    (1.0, 2.0, 3), # TypeError
    (1.0, 2.0, np.float64(3.0)), # ok (yes!)
    (1, 2.0, np.float32(3)), # TypeError
    (1, 2.0, np.uint8(3)), # TypeError
):
    try:
        foo( data )
    except TypeError:
        print('expected TypeError:', data)