python的type hints(类型标注、类型注解、类型提示)

1. 前言

  type hints(类型标注、类型注解、类型提示)是指在代码中涉及到数据交互的地方,提供数据类型的注解(显式的说明)。类型注解可以帮助第三方IDE工具(PyCharm)对代码进行类型推断,协助做代码提示;能帮助开发者自身对变量进行类型标注。类型注解可分为:变量的类型注解、函数(方法)形参列表和返回值的类型注解。总而言之,加上注解之后,我们可以直观的看出变量、函数(方法)参数列表和返回值到底是个什么东西(什么类型)。

2. 简单的类型注解

  简单的类型注解(基本类型注解):可以使用int、str和list等基本类型来注解变量、函数参数和返回值的类型。

2.1 变量的类型注解

  为变量设置类型注解,语法格式为:变量: 类型,代码示例如下。

num: int = 10
s: str = "hello"
my_list: list = [1,2,3,4]
my_tuple: tuple = (1,2,3)

class Student:
	pass
stu: Student = Student()

除了使用变量: 类型这种格式外,还可以在注释中进行类型注解,语法:# type: 类型,示例代码如下。

num = 10  # type: int
s = "hello"  # type: str
my_list = [1,2,3,4]  # type: list
my_tuple = (1,2,3)  # type: tuple

2.2 函数(方法)的类型注解

   给函数(方法)形参类型和返回值类型进行标注,定义语法如下:

def 函数(或方法)名(形参1: 类型, 形参2: 类型, ...) -> 返回值类型:
    pass

示例代码如下。函数注解的信息,保存在__annotations__属性中可以来调用。

def sum(x: int, y: int) -> int:
    return x+y
    
sum(1,2)
print(sum.__annotations__)
# 输出:{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}

2.3 安装mypy

  注意:类型注解仅仅是提示性的,不是决定性的,就算你类型注解错误也不会报错。像下面的代码就不会报错:变量num的类型注解为int,却把字符串"hello"赋给它了;变量s的类型注解为str,却把整数10赋给它了;函数sum的形参x,y和返回值都是int类型,却把字符串"hello"和"world"分别赋给参数x,y。

num: int = "hello"
s: str = 10

def sum(x: int, y: int) -> int:
    return x+y

print(sum(1,2))
print(sum("hello ","world"))

  我们可以通过mypy库来检验最终代码是否符合设定的类型注解。mypy是python中有关类型的静态分析工具。

#安装 mypy
pip install mypy

# 执行下面代码来查看是否符合设定的类型注解
mypy test.py

3. 标准库typing模块

   上面只是简单的类型注解,传入的类型表述能力有限,不能说明复杂的类型组成情况,因此可以引入typing模块来实现复杂的类型表达,typing是在python 3.5 才开始有的模块。

3.1 List, Tuple, Set, Dict基础用法

(1)List[int]表示由整数(int)组成的列表;
(2)Tuple[int, str, bool]表示由三个对象组成的元组,其中这三个对象的类型分别为int, str, bool;
(3)Set[int]表示由整数(int)组成的集合;
(4)Dict[int, str]表示键是int,值是str的字典。

代码示例如下

from typing import List, Tuple, Set, Dict

my_list: List[int] = [1, 2, 3, 4, 5, 6]
my_tuple: Tuple[int, str, bool] = (1, "hi", True)
my_set: Set[int] = {1, 2, 3}
my_dict: Dict[int, str] = {1: "a", 2: "b", 3: "c"}

3.2 Union和Optional

  对于更为复杂的类型注解,我们可以使用联合类型注解Uniontyping模块中的Union可以给一个变量或函数返回值标注多种类型,它表示的意思。例如:data: Union[str, bytes],变量data可以是str类型或bytes类型。在Python 3.10版本及以后,推荐使用|运算符代替Union。示例代码如下:

from typing import Union

my_list: List[Union[int,str]] = [1,3,5,"hello,"world"]
my_dict: Dict[str, Union[str, int]]= {"name": "Jack", "age": 16}

(1)List[Union[str,int]]:该列表中的元素可以是int类型的对象,也可以是str类型的对象;
(2)Dict[str, Union[str, int]]:该字典中的键为str,值是str和int都可以。

  typing模块中的Optional类型,它是Union的一个特殊情况。如果一个变量可以是None或其他类型,推荐使用Optional类型,其中Optional[int]等价于Union[int, None]Optional[Union[str, int, float]]等价于Union[str, int, float, None]。对了,Optional[]里面只能写一个数据类型,代码示例如下

num1: Optional[Union[int, str, float]] = None
num2: Union[int, str, float,None] = None

3.3 类型别名(type alias)

  因为在python中一切皆为对象,所以可将复杂一点的类型赋给某个变量,也就是起个别名,这样使用起来较为方便。

var_int = int
num1: int = 10
num2: var_int
# 以上两种类型注解的方式等价

from typing import List, Dict

list_alias = List[int]
dict_alias = Dict[str, list_alias]
my_dict: dict_alias = {"a": [1,2,3], "b": [4,5,6]}
# 以上两种类型注解的方式等价

3.4 Callable

  Callable是一个可调用对象类型,语法格式为:Callable[[参数类型], 返回类型],包括可调用对象的参数类型和返回值类型。例如:Callable[[int], str],这里的int表示可调用对象的参数类型,str代表可调用对象的返回值类型。

from typing import Callable

def print_name(name: str) -> None:
    print(f"name:{name}")

def get_name(func: Callable[[str], None]):
    return func

# 利用isinstance(对象, Callable)来判断当前对象是否为可调用对象
# print(isinstance(print_name, Callable))  # 输出 True

fun = get_name(print_name)
fun("zhangsan")

3.5 TypeVar和Generic

  泛型是一种可以在不指定具体类型的情况下编写可复用代码的技术。Python中的泛型是使用typing模块中的TypeVarGeneric进行实现的。TypeVar用于定义泛型类型变量,而Generic用于定义泛型类。

  (1)泛型类型变量:用于表示不确定的类型。泛型类型变量通常使用大写字母命名,比如 T、U、V。

T = TypeVar('T')  # 创建一个泛型类型变量T,T可以是任意类型

  (2)泛型函数:是可以接受一个或多个泛型类型参数的函数,这些参数可以用来指定函数参数的类型、返回值的类型或函数内部使用的其他类型。

from typing import TypeVar,List

T = TypeVar('T')

def print_list(my_list: List[T]) -> None:
    print(my_list)

print_list([2,4,6,8])  # 可以打印整数列表
print_list(["hh","aa","www"])  # 可以打印字符串列表

  (3)约束泛型:有时候我们希望泛型类型只能是特定的类型,在这种情况下,我们可以使用泛型约束来限制泛型类型的范围。

from typing import TypeVar,List

T = TypeVar('T',int,float)  # 泛型类型变量T可以是int,也可以是float类型

def print_list(my_list: List[T]) -> None:
    print(my_list)

print_list([2,4,6,8])  # 可以打印整数列表
print_list([1.2, 2.3, 3.4])  # 可以打印浮点数列表

  (4)泛型类:是可以接受一个或多个泛型类型参数的类。这些参数可以用来指定类的属性类型、方法参数类型、方法返回值类型或类内部使用的其他类型。

from typing import TypeVar, Generic

T = TypeVar('T')

class Student(Generic[T]):  # 继承Generic[T],
    def __init__(self, name: T) -> None:
        self.name = name

    def get_name(self) -> T:
        return self.name
    
stu = Student[str]("zhangsan")  # 或者stu = Student("zhangsan")
print(stu.get_name())  # 输出:zhangsan

3.6 Any 类型

  静态类型检查器将所有类型视为与Any兼容,这意味着可对类型为Any的值执行任何操作或方法调用,并将其赋值给任何变量。

from typing import Any

a = 10 # 变量a在默认情况下为Any类型

def print_info(var: Any) -> None:
    print(var)

print_info(11)
print([1,2,3,4])
print("string")

最后再说一句:如果你按照规范的格式进行类型注解,却发现报错误,那很大可能是python版本太低。比如下面代码中的类型注解就是在python 3.10开始支持的,3.10版本以下的不支持该语法格式的类型注解。

x: int | float = 2 # 表示 or Python 3.10 开始支持

参考文章:
Python 标准库 typing 类型注解标注
typing —— 对类型提示的支持

  • 21
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值