Python3 Typing模块详解
原创关注公众号查看作者更多文章,公众号:海天二路搬砖工
一、引言
在 Python 3 之前,Python 是一种弱类型语言,类型是不显式地声明的,Python 可以在运行时根据上下文自动推断出变量或参数的类型。这一特性常常导致程序运行时因类型不匹配而引发一系列异常,给程序员带来了很大的困扰。
为此,Python3中引入了静态类型注解(Type hints),用于在 Python 代码中显式地注明变量、函数参数和函数返回值的类型。
typing
模块是为 Python 提供静态类型注解的一组工具,它使 Python 开发者能够清晰明了地注释变量、方法和函数的数据类型。
二、Typing模块简介
typing
模块是 Python 3 中新增加的模块,它是一组静态类型注解工具。
typing
模块的作用
-
类型注释:
typing
模块提供了大量用于类型注释的工具,并使开发人员能够使用自己自定义数据类型。通过将这些类型注释添加到变量、函数、类、方法、属性等数据结构中,可以更清晰、易于理解地表示数据类型,有助于其他人更好地理解代码。 -
类型检查:
因为 Python 是一门动态类型语言,导致类型错误容易在运行时发生。
typing
模块允许静态类型检查,这是在运行之前在代码中检测类型错误的过程,这可帮助程序员尽早发现和修复任何类型相关的错误,并提高代码质量。 -
数据容器:
typing
模块中提供了非常强大的数据容器类型,如List
、Tuple
、Dict
和Set
等,帮助开发人员更有效地操作数据结构。通过使用typing,我们可以使用Python语言提供的丰富数据结构,并用更准确的方式进行标注和注释。 -
泛型编程支持:
typing
提供了定义泛型类和函数的快捷方式,提供了思考和解决泛型编程的强有力的支持。 -
类型别名:
typing
模块允许开发人员创建自己的类型别名,以提高代码的可读性和可维护性。这可让类型字典更简洁,同时确保它们与代码实际使用的类型一致。 - 增强可读性: 通过使用typing模块提供的类型注释,我们可以使代码更具可读性和可理解性,有助于开发人员能够更好地阅读和理解代码。
三、 基本类型注释
最基本的类型注释(
int
、
str
、
bool
等)
typing
模块定义了一些最基本的数据类型别名,如
int
、
float
、
str
、
bool
等。它可以与参数、变量和函数返回值一起使用。
def greeting(name: str) -> str:
接收 str 类型参数 name,返回 str 类型。
return 'Hello ' + name
在这个示例中,参数 name 被注释为 str 类型,返回类型也被注释为 str 类型。
Union
类型注释
Union
类型允许同时使用多个数据类型,其中任何一种类型的值都可以传递给函数。在注释中,我们使用 or 或 | 分隔多个数据类型。
from typing import Union
def get_user_input() -> Union[str, int]:
该函数返回 str 或 int 数据类型结果。
user_input = input("Please enter an integer or string: ")
if user_input.isdigit():
return int(user_input)
else:
return user_input
Optional
类型注释
Optional
类型表示一个可选的数据类型,它可用于表示参数可以是一种数据类型或 None 值。我们使用
Optional[type]
表示该函数参数可以是
type
或
None
值。
from typing import Optional
def get_username() -> Optional[str]:
当获取到正确的用户名时,返回 str 类型数据;否则返回 None。
username = input("Please enter your username: ")
if username:
return str(username)
except:
return None
在这个示例中,我们使用
Optional[str]
来表示
get_username()
函数返回
str
类型数据或
None
值。
四、 容器类类型注释
简单的容器类型注释
typing模块对常用的容器类型提供了类型注释关键字
List
、
Tuple
、
Dict
和
Set
。
-
List
类型注释:List
的类型注释中使用方括号来指定列表中每个元素的类型。 -
Tuple
类型注释:Tuple
类型注释可以使用方括号表示Tuple中每个元素数据类型。我们也可以使用...允许将数量未知的元素包括在 Tuple 数据类型之中。 -
Dict
类型注释:Dict
类型注释使用键和值的数据类型注释来描述一个字典的键和值。 -
**Set
类型注释**:Set
类型注释可以用花括号和 Set 关键字来表示,用于指定集合中元素的类型。
**List
示例:**
from typing import List
def sort_numbers(numbers: List[int]) -> List[int]:
接收一个整数列表,并返回按照升序排列后的列表。
return sorted(numbers)
在这个示例中,我们使用
List[int]
将 numbers 参数注释为整数类型列表。
Dict
示例:
from typing import Dict
def user_info(name: str, age: int) -> Dict[str, Union[str, int]]:
接受用户名和年龄,返回一个包含用户名和年龄的字典。
user = {}
user['name'] = name
user['age'] = age
return user
在这个示例中,我们使用
Dict[str,Union[str, int]]
将函数的返回类型注释为一个字典,包含字符串类型的键和字符串或整型的值。
嵌套的容器类型
嵌套容器(Nested container)是指容器中又包含其他容器。
typing
模块为这种数据类型提供了更复杂的注释方式。
from typing import List, Tuple
def my_function(arg1: List[Tuple[int, str]]) -> List[str]:
接受一个整型列表中包含元组(整型,字符串),返回由元组中包含的字符串组成的列表。
return [x[1] for x in arg1]
在这个示例中,参数
arg1
被注释为一个
List
,每个元素都是一个
Tuple
,其中第一个元素是
int
类型,第二个元素是
str
类型。函数的返回类型为
List[str]
数据类型,一个字符串类型的列表。
五、
Callable
类型注释
**
Callable
**类型注释和它们的变体
typing
模块提供了可以用来注释函数类型的
Callable
类型,包括
Callable[[args], return_type]
以及
Callable[..., return_type]
。
(1)
Callable[[args], return_type]
的注释使用方括号,
args
表示函数参数的类型,
return_type
表示函数返回值的类型。
from typing import Callable
def repeat(word: str, times: int, callback: Callable[[str, int], str]) -> None:
接收字符串word、重复次数times和一个回调函数,它会使用回调函数重复一个词给定的次数。
for i in range(times):
result = callback(word, i)
print(result)
(2)
Callable[..., return_type]
的注释使用省略符、返回值类型表示被调用的函数的返回值类型。省略号表示这个函数任意数量和类型的参数,也就是说这个函数类型可以接受任意数量和类型的参数。
from typing import Callable
def logger(func: Callable[..., str]) -> Callable[..., str]:
def wrapped(*args, **kwargs) -> str:
result = func(*args, **kwargs)
print("Got result: ", result)
return result
return wrapped
在这个示例中,使用 Callable[..., str] 将一个函数类型的 func 参数注释为一个可调用的函数类型,它的返回值是 str 类型,同时使用 *args 和 **kwargs 参数传递任意数量和类型的参数。
使用**
Callable
**类型来给函数参数和返回值加上类型注释
可以将
Callable
类型注释用于函数的参数和返回值,
from typing import Callable
def apply_operation(func: Callable[[int, int], int], a: int, b: int) -> int:
接受两个整型变量 a 和 b 以及一个将整型变量映射到整型变量的函数func,返回这个函数的执行结果。
return func(a, b)
def add(a: int, b: int) -> int:
返回 a + b 的和
return a + b
def multi(a: int, b: int) -> int:
返回 a * b 的积
return a * b
result_add = apply_operation(add, 4, 5)
result_multi = apply_operation(multi, 4, 5)
六、 类型别名(Type Aliases)
什么是类型别名
类型别名是指我们可以使用一个给定的名称将一个数据类型表示成等效的形式,这种方式可以简化代码的阅读和理解。
typing
模块提供了一个
TypeAlias
类型,用于给数据类型定义别名。
from typing import List, TypeAlias
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector:
接受一个浮点类型的倍数 scalar 和一个 float 类型的 Vector 列表,返回一个缩放后的 Vector。
return [scalar * num for num in vector]
new_vector = scale(2.0, [1.0, -4.2, 5.4])
这个示例中,我们定义了一个名为 Vector 的类型别名,它表示一个 float 类型的列表。函数 scale() 就使用了这个别名。
使用类型别名来简化类型注释
类型别名可以用于把复杂的类型注释简单化:
from typing import Dict, List, Union
UserInfo = Dict[str, Union[str, int]]
AddressBook = List[UserInfo]
def showbook(book: AddressBook) -> None:
接收一个 AddressBook 类型的参数并打印其中的用户信息
for user in book:
print(f"Name: {user['name']}")
print(f"Age: {user['age']}")
print(f"Address: {user['address']}")
def add_user(book: AddressBook, name: str, age: int, address: str) -> None:
将一名新用户添加到 AddressBook 中,并写入磁盘。
new_user = UserInfo(name=name, age=age, address=address)
book.append(new_user)
write_to_disk(book)
def write_to_disk(book: AddressBook) -> None:
将整个 AddressBook 列表写入磁盘文件。
# 实现将 book 写入磁盘代码
pass
在这个示例中,我们使用类型别名的方式来简化代码的类型注释,用
UserInfo
表示一个字典类型,表示的是一个用户信息; 用 AddressBook 表示一个列表类型,其中每个元素都是一个
UserInfo
类型的字典。
创建自定义类型别名
我们可以使用 TypeAlias 的类型别名来定义自己的数据类型。一个类型别名可以用于多个数据类型的定义.
from typing import TypeAlias, Union
Number = Union[int, float, complex]
Matrix = List[List[Number]]
def add_matrices(a: Matrix, b: Matrix) -> Matrix:
接收两个 Number 类型列表,并返回其劈叉后的 Matrix 类型。
if len(a) != len(b) or len(a[0]) != len(b[0]):
raise ValueError("Matrices have different size")
res = []
for i in range(len(a)):
res.append([])
for j in range(len(a[0])):
res[i].append(a[i][j] + b[i][j])
return res
在这个示例中,我们定义了 Number 类型别名表示 float、int、complex 三种数据类型中的任意一种。同时,我们使用 Matrix 类型别名表示二维数组,其中的元素可以是 Number 类型别名中定义的任意一种类型。
七、
typing
与泛型编程
什么是泛型编程
泛型编程是一种编程方法,它允许你写出更加通用、灵活、可复用的代码。使用泛型编程,可以定义函数和类,并允许它们在运行时接受不同类型的参数和数据结构。
在 Python 中,我们可以使用 typing 模块来实现泛型编程。typing 模块提供了大量的类型,包括数字、列表、字典、元组等常见的数据类型,并且使用泛型类型注释来描述容器类型中的元素类型和数量。
泛型函数与泛型类
泛型类型注释允许我们定义泛型函数和泛型类,可以将这些类型注释用于函数的参数、返回值和函数本身。泛型类型注释用于泛型函数和泛型类时,这些函数和类将接受不同类型的参数,并在运行时创建新的类型。
泛型函数:
from typing import TypeVar
T = TypeVar('T')
def reverse_list(lst: List[T]) -> List[T]:
返回一个反转后的列表
return lst[::-1]
在这个函数中,我们使用了泛型类型变量 T 来表示列表里的元素类型,这样就可以处理任何类型的列表。
List[T]
表示一个元素为 T 类型的列表,因此
reverse_list
函数可以应用于任何类型的列表。
泛型类:
from typing import TypeVar, Generic
T = TypeVar('T')
class Queue(Generic[T]):
一个泛型队列类
def __init__(self):
self.items = []
def enqueue(self, item: T) -> None:
将元素添加到队列的末尾
self.items.append(item)
def dequeue(self) -> T:
从队列的前面删除并返回第一个元素