【问题标题】:Is there a preferable way to create type aliases for compound types with Python's typing module?有没有更好的方法来使用 Python 的类型模块为复合类型创建类型别名?
【发布时间】:2021-12-06 12:51:45
【问题描述】:

我有一个带有一个参数的函数,它应该以intNone 作为参数。有几种方法可以为这种复合类型创建类型别名:

# test.py
import typing

IntOrNone_1 = typing.TypeVar('IntOrNone_1', int, None)
IntOrNone_2 = typing.Union[int, None]


def my_func1(xyz: IntOrNone_1):
    return xyz

def my_func2(xyz: IntOrNone_2):
    return xyz


my_func1(12)
my_func1(None)
my_func1(13.7)
my_func1('str')

my_func2(12)
my_func2(None)
my_func2(13.7)
my_func2('str')

这两种方法都按照我的预期做,但是,对应的mypy erros 略有不同,但基本上具有相同的含义。

test.py:14:错误:“my_func1”的类型变量“IntOrNone_1”的值 不能“浮动”

test.py:15:错误:“my_func1”的类型变量“IntOrNone_1”的值 不能是“str”

test.py:19:错误:“my_func2”的参数 1 具有不兼容的类型 “漂浮”;预期“可选[int]”

test.py:20:错误:“my_func2”的参数 1 具有不兼容的类型 “str”;预期“可选[int]”

我倾向于使用第二种方法,因为它还会报告导致错误的参数。

我认为这两种方法确实是等效的,还是其中一种方法更受欢迎?

【问题讨论】:

标签: python typing typechecking


【解决方案1】:

这两种方法远非等价。您应该避免将 TypeVar 视为仅仅是别名——相反,它们是您想要使您的函数通用时使用的更特殊的形式。

用一个例子来解释什么是“泛型函数”是最简单的。假设您要编写一个函数,该函数接受某个对象(任何对象!)并返回另一个 完全相同类型的对象。你会怎么做呢?

我们可以做的一种方法是尝试使用object

def identity(x: object) -> object:
    return x

这让我们接近了,因为我们的 identity 函数至少可以接受任何字面意思(因为所有类型都继承自 Python 中的 object)。然而,这个解决方案是有缺陷的:如果我们传入一个 int,我们会返回 object,这不是我们想要的。

相反,我们需要的是一种让类型检查器了解这两种类型之间存在“关系”的方法。这正是TypeVar 派上用场的地方:

T = TypeVar('T')

def identity(x: T) -> T:
    return x

在这种情况下,我们的 TypeVar 'T' 充当“占位符”,可以绑定到我们想要的任何类型。因此,如果我们执行identity(3)T绑定int——因此类型检查器将因此理解返回类型也必须是int

如果我们在参数类型提示中多次使用T,类型检查器将确保每次类型都相同。


那么,下面的表达式是做什么的呢?

IntOrNone_1 = typing.TypeVar('IntOrNone_1', int, None)

好吧,事实证明,将 约束 添加到我们的特殊占位符类型有时会很有用。例如,您已约束 IntOrNone_1,使其只能绑定到 intNone,而不能绑定到其他类型。


最后,回答您的最后一个问题:在您给出的示例中,您绝对应该使用 Union,而不是 TypeVars。

是否使用 Union 或 Union 的类型别名确实是个人喜好问题,但如果您不需要这种“占位符”或“通用”行为,则不应使用 TypeVars。

如果您想了解有关如何使用 TypeVars 的更多信息,mypy 文档有一个 section on generics。它涵盖了我跳过的几件事,包括如何制作泛型类(不仅仅是泛型函数)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多