类型提示概念以改进 Python 代码

2024 年 08 月 29 日 | 阅读 9 分钟

在本教程中,我们将讨论有助于提高代码可读性和增强代码结构的类型提示概念。我们将讨论一些类型提示技巧,这些技巧将使 Python 程序更具可读性。

正如我们所知,Python 是一种动态类型编程语言。这意味着解释器在代码运行时逐行检查代码,并且变量类型在其生命周期中可以更改。让我们了解与类型提示相关的以下重要概念。

1. 类型注解

类型提示使用 Python 注解进行,并用于为变量、参数、返回值、类属性和方法添加类型。类型提示在运行时不受影响,因为它们只是提示。Python 解释器始终会忽略它们。

1. 变量注解 -

变量注解遵循以下语法 -

我们可以使用 Python 内置数据类型之一来执行类型提示,例如 int、float、str、bool、bytes、list、tuple、dict、set、frozenset 和 None。

让我们理解下面的例子。

示例 -

2. 函数注解

我们还可以将类型提示与函数一起使用,以指定其参数和返回值的类型。可以使用之前的语法指定参数的类型。让我们通过以下示例了解 -

示例 -

如果函数不返回任何内容,您可以将返回类型(箭头之后)设置为 None。

3. 类注解

我们甚至可以在 Python 类中的属性和方法上添加注解。

2. 列表

假设我们正在使用一个函数,该函数接受一个由浮点数列表组成的复杂参数。我们可以如下进行注解。

示例 -

这似乎是正确的,但它不起作用。要使其正常工作,我们需要将内置的标准列表类型替换为我们可以从 typing 模块导入的 List 类型。List 类型的好处是它可以包含任何类型的元素。让我们看以下修改后的示例

示例 -

我们可以注解字符串列表的列表。

示例 -

3. 字典

为了确保对字典中键和值的类型进行控制,您可以使用 Python 的 `typing` 模块中的 `Dict` 类型。这允许您指定字典中键和值的预期类型。

通过使用 `Dict` 类型,您可以定义一个具有特定键和值类型的字典,从而提供清晰度并强制执行所需的模式。例如,您可以使用 `Dict[str, Dict]` 创建一个带有字符串键和字典值的字典。这表示键应为 `str` 类型,而值应为 `Dict` 类型(在这种情况下,表示嵌套字典结构)。

使用 `Dict` 类型有助于维护字典的预期类型和结构,使其更容易理解和处理数据。

我们正在处理带有字符串键和字典值的字典。

要使用类型提示,我们可以将两个参数传递给 Dict,其中第一个是键的类型,第二个是值的类型。

4. Union(联合)

在 Python 3.10 的新版本中,Union 被 | 取代,这意味着 Union[X. Y] 等同于 X | Y。让我们通过以下示例了解。

示例 -

我们有一个函数,用于从缓存目录读取文件。此缓存目录位置可以是字符串值,也可以是 Pathlib 库中的 Path 对象。

4. TypedDict

typing 模块中的 TypedDict 类型允许我们声明一个具有特定键集的字典类型,其中每个键都与具有一致类型的对应值相关联。以下是一个演示 TypedDict 用法的示例。

示例 -

输出

John Doe
30
123 Main St

解释 -

在上面的示例中,我们定义了一个继承自 TypedDict 的 Person 类。在类内部,我们声明了预期的键(name、age 和 address)以及它们对应的值的类型(分别为 str、int 和 str)。

然后,我们创建了一个名为 person 的 Person TypedDict 实例,并为每个键分配了值。这些值必须符合声明的值类型。

最后,我们可以使用相应的键访问并打印 person 字典中的值。

请注意,TypedDict 从 Python 3.8 开始可用。如果您使用的是旧版本,则可能需要使用 typing_extensions 等第三方库来获得类似的功能。

5. Callable(可调用)

Python 中的 Callable 类型提示允许您指定变量或函数参数应该是可调用对象,例如函数或方法。它允许您定义可调用对象的预期签名,包括其参数的类型和返回值。

输出

20

解释 -

在上面的示例中,我们有一个 apply_operation 函数,它接受两个整数(a 和 b)和一个可调用操作作为参数。operation 参数使用 Callable 类型提示进行了注解,指定它应该是一个可调用对象,该对象接受两个 int 参数并返回一个 int。

我们定义了一个单独的 multiply 函数,它匹配 Callable 类型提示指定的签名。它接受两个整数并返回它们的乘积。

当使用 4、5 和 multiply 调用 apply_operation 时,该函数会使用提供的参数进行调用。它将 multiply 函数作为操作应用并返回结果,然后打印结果(在本例中为 20)。

Callable 类型提示提供了一种定义和强制执行可调用对象的预期行为的方式,使您的代码更具表达力并支持更好的类型检查。

6. Any(任意)

Python 中的 Any 类型提示表示任何类型的value。当您想指示变量、函数参数或返回值可以是任何类型时,可以使用它。让我们通过以下代码了解。

示例 -

输出

"42"

7. Optional(可选)

在 Python 中,您可以使用可选类型提示来指示变量或函数参数可能具有特定类型或可能为 None。可选类型提示由 Union 类型提示表示,它允许多种可能的类型,包括 None。

以下是有关如何使用可选类型提示的示例

示例 -

输出

Hello, Alice!
Hello!

示例 -

在上面的示例中,greet 函数的 **name** 参数用 **Optional[str]** 注解,表示它可以是字符串或 None。在函数内部,我们检查 `name` 是否为 None,如果是,则返回通用问候语,如果提供了名称,则返回个性化问候语。

使用可选类型提示可以帮助提高代码的可读性,并在使用 mypy 等类型检查器进行静态分析时捕获潜在的类型相关错误。但是,需要注意的是,Python 中的类型提示是可选的,不会影响代码的运行时行为。它们主要用于文档和静态分析。

8. Sequence(序列)

Sequence 类型提示可以是任何类型的序列,例如列表、元组、字符串、对象列表等。typing 模块为此目的提供了 Sequence 类型提示。让我们通过以下示例了解。

示例 -

输出

15

解释 -

在上面的示例中,process_numbers 函数的 numbers 参数用 Sequence[int] 注解,表示它应该是一个包含整数的序列(列表、元组等)。在函数内部,我们迭代序列中的元素并计算它们的总和。

通过使用 Sequence 类型提示,您可以向其他开发人员和静态分析器明确表示预期的输入是序列。这有助于提高代码的可读性,并在静态分析期间捕获潜在的类型相关错误。

需要注意的是,Sequence 类型提示是一个泛型类型提示,您可以通过在方括号内提供类型参数来指定序列中元素的类型,如示例所示(Sequence [int])。

9. Tuple(元组)

在 Python 中,我们可以使用元组类型提示来指示变量或函数参数应该是元组。typing 模块为此提供了 `Tuple` 类型提示。

以下是有关如何使用 `Tuple` 类型提示的示例

示例 -

输出

5.0

解释 -

在上面的示例中,process_coordinates() 函数的 **coordinates** 参数用 Tuple[float, float] 注解,表示它应该是一个包含两个浮点数的元组。在函数内部,我们将元组解包到 x 和 y 变量中,并使用勾股定理计算欧几里得距离。

通过使用 Tuple 类型提示,您可以向其他开发人员和静态分析器明确表示预期的输入是元组。这有助于提高代码的可读性,并在静态分析期间捕获潜在的类型相关错误。

需要注意的是,Tuple 类型提示是一个泛型类型提示,我们可以通过在方括号内提供类型参数来指定元组中元素的类型,如示例所示(Tuple[float, float])。类型参数的数量和顺序应与元组中元素的数量和顺序相匹配。

在代码中使用类型提示的优点

以下是类型提示的主要优点。

  • 类型提示在函数中非常有用,我们可以提供信息丰富的签名,以阐明有关函数参数和返回结果的假设。
  • 类型提示可提高代码的可读性、可维护性和调试性。显式类型信息可减少认知负担,从而更容易推理对象及其关系,从而实现更健壮和可靠的软件开发。

结论

类型提示为我们的代码引入了额外的抽象层,可用于多种目的。它们充当文档,阐明输入和输出的假设,同时也有助于在静态代码分析(例如使用 mypy 等工具)期间检测细微错误。

通过包含类型提示,我们在代码中提供了一种自我文档的形式。这些提示描述了变量、函数参数和返回值的预期类型,使其他人(包括您未来的自己)更容易理解代码的预期用途和行为。

在某些情况下,建议不要添加类型提示,特别是在使用旧版 Python、刚开始学习编程语言或性能是关键问题时。值得注意的是,类型提示可能会在启动时间方面带来轻微的开销。


下一个主题Python 中的向量化