typing
Python是一门动态语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果,就不得不去阅读代码的具体内容,降低了阅读的速度,typing模块可以很好的解决这个问题。
Python的typing包是从Python 3.5版本引入的标准库,它提供了类型提示和类型注解的功能,用于对代码进行静态类型检查和类型推断。typing模块中定义了多种类型和泛型,以帮助开发者代码的可读性、可维护性和可靠性。
typing的作用
typing包的主要功能如下:
- 类型注解:typing包提供了多种用于类型注解的工具,包括基本类型(如int、str)、容器类型(如List、Dict)、函数类型(如Callable、Tuple)、泛型(如Generic、TypeVar)等。通过类型注解,可以在函数声明、变量声明和类声明中指定参数的类型、返回值的类型等,以增加代码的可读性和可靠性。
- 类型检查:通过与第三方工具(如mypy)集成,可以对使用了类型注解的代码进行静态类型检查。类型检查可以帮助发现潜在的类型错误和逻辑错误,以提前捕获问题并改善代码的质量。
- 泛型支持:typing模块提供了对泛型的支持,使得可以编写更通用和灵活的代码。通过泛型,可以在函数和类中引入类型参数,以处理各种类型的数据。
- 类、函数和变量装饰器:typing模块提供了一些装饰器,如@overload、@abstractmethod、@final等,用于修饰类、函数和变量,以增加代码的可读性和可靠性。
除了typing包,还有typing_extensions模块,它是typing模块的扩展,提供了一些额外的功能和类型。typing_extensions中包括了一些高级的类型工具和类型别名,用于更复杂的类型定义和注解。
总的来说,typing包和typing_extensions模块为Python开发者提供了一套强大的类型提示工具,使得可以在代码中加入类型注解,并通过类型检查工具提供静态类型检查的功能,以提高代码的可读性和质量。
即, typing是python 3.5及以后版本的标准库,typing_extensions是typing模块的扩展包。
typing常用类型
以下是typing包中常用的类型和泛型。
注意:
- int, float, bool, str, bytes 不需要 import typing
- Any,Union,Tuple 等 需要 import typing
-
基本类型:
- int: 整数类型
- float: 浮点数类型
- bool: 布尔类型
- str: 字符串类型
- bytes: 字节类型
- Any: 任意类型
- Union: 多个类型的联合类型,表示可以是其中任意一个类型
- Tuple: 固定长度的元组类型
- List: 列表类型
- Dict: 字典类型,用于键值对的映射
-
泛型:
- Generic: 泛型基类,用于创建泛型类或泛型函数
- TypeVar: 类型变量,用于创建表示不确定类型的占位符
- Callable: 可调用对象类型,用于表示函数类型
- Optional: 可选类型,表示一个值可以为指定类型或None
- Iterable: 可迭代对象类型
- Mapping: 映射类型,用于表示键值对的映射
- Sequence: 序列类型,用于表示有序集合类型
- Type:泛型类,用于表示类型本身
typing使用示例
# fun1里,标明了形参和返回值的类型,fun2中却没有。
# 由于fun1里有了完整的变量类型的注释,通过help查看其使用文档就很清楚知道怎么用该函数。
from typing import List, Tuple, Dict
def fun1(a0: int, s0: str, f0: float, b0: bool) -> Tuple[List, Tuple, Dict, bool]:
list1 = list(range(a0))
tup1 = (a0, s0, f0, b0)
dict1 = {s0: f0}
b1 = b0
return list1, tup1, dict1, b1
def fun2(a0, s0, f0, b0):
list1 = list(range(a0))
tup1 = (a0, s0, f0, b0)
dict1 = {s0: f0}
b1 = b0
return list1, tup1, dict1, b1
print(fun1(5, "KeyName", 2.3, False))
# ([0, 1, 2, 3, 4], (5, 'KeyName', 2.3, False), {'KeyName': 2.3}, False)
print(fun2(5, "KeyName", 2.3, False))
# ([0, 1, 2, 3, 4], (5, 'KeyName', 2.3, False), {'KeyName': 2.3}, False)
print(help(fun1))
"""
Help on function fun1 in module __main__:
fun1(a0: int, s0: str, f0: float, b0: bool) -> Tuple[List, Tuple, Dict, bool]
"""
print(help(fun2))
"""
Help on function fun2 in module __main__:
fun2(a0, s0, f0, b0)
"""
([0, 1, 2, 3, 4], (5, 'KeyName', 2.3, False), {'KeyName': 2.3}, False)
([0, 1, 2, 3, 4], (5, 'KeyName', 2.3, False), {'KeyName': 2.3}, False)
Help on function fun1 in module__main__:
fun1(a0: int, s0: str, f0: float, b0: bool) -> Tuple[List, Tuple, Dict, bool]
None
Help on function fun2 in module__main__:
fun2(a0, s0, f0, b0)
None
'\nHelp on function fun2 in module__main__:\nfun2(a0, s0, f0, b0)\n'
from typing import List
def func(a: int,b: str) -> List[int or str]:# 使用or关键字表示多种类型
list1 = []
list1.append(a)
list1.append(b)
return list1
l = func(3, "aa")
print(l) # [3, 'aa']
[3, 'aa']
[3.0, 'aa']
# 定义一个不确定类型的占位符T,用作函数foo的形参, 但函数返回值一定是str,通过内部做str(name)转化来保证。
import typing
T=typing.TypeVar('T',int,float,str)
def foo(name:T)->str:
return str(name)
print(foo(2.012)) # 2.012
print(foo(35)) # 35
print(foo("hahaha")) # hahaha
# typing中的Type是一个泛型类,用于表示类型本身,即你是啥类型就是啥类型,有点绕,看例子吧:
from typing import Type
value: Type[int] # value是一个Type对象,表示int类型
value: int
# 即value:Type[int]和value:int是等价的。
# 那为什么还要有这个Type类呢,我理解它为一个更为宽松的类型标注,比如下面函数:
# tvm.py
def ir_module(mod: Type) -> IRModule:
"""The parsing method for ir module, by using `@ir_module` as decorator.
Parameters
----------
mod : Type
The class to be parsed as ir module.
Returns
-------
ir_module : IRModule
The parsed ir module.
"""
if not inspect.isclass(mod):
raise TypeError(f"Expect a class, but got: {mod}")
m = parse(mod, utils.inspect_class_capture(mod))
setattr(m, "__name__", mod.__name__)
return m
# 这个ir_module()作为一个装饰器,mod传进来是啥就是啥,但必须要是一个类型。
# 然后在函数里,通过inspect强制检查mod必须为一个类,不然就报错。我们在使用ir_module装饰器时,一般是这样的:
import tvm
from tvm.ir.module import IRModule
from tvm.script import tir as T
@tvm.script.ir_module
class MyModule:
pass
ir_mod = MyModule
print("done")
# 即给ir_module传进去的是MyModule这个类。
# Type也可用于标注函数返回值类型,比如
from typing import Type, List
def get_list_type() -> Type[List[int]]:
return list
returned_type = get_list_type() # returned_type是一个Type对象,表示List[int]类型
# 在上述示例中,Type[List[int]]表示List[int]类型本身,可以用于注解函数get_list_type的返回类型,说明该函数返回的是List[int]类型的值。
# 通过调用get_list_type()函数得到的返回值returned_type是一个Type对象,表示List[int]类型。
# 或标注函数参数类型:
from typing import Type
def process_type(t: Type[str]) -> None:
print(t)
process_type(str) # 输出: <class 'str'>
# 在上述示例中,Type[str]用于注解函数process_type的参数类型,说明函数接受一个类型为str的参数。
# 通过在调用process_type函数时传入str作为参数,可以在函数内部获取到该类型的Type对象。