在前面我们介绍了许多种Python的内置类型,也介绍了如何自定义类型,但是我们在声明变量的时候都没有声明它的类型,只有在变量运行的时候,根据变量的赋值才能确定变量的类型。

Python因为这种特性,我们把它称为动态类型语言(或者叫弱类型语言),因为它只有在执行的时候,才能确定变量的类型。动态类型语言有很多优势,但是也有很大的弊病,就是在函数传递参数的时候,很容易把参数的类型传递错误,从而引发函数调用的异常。

相比动态类型语言,像C/C++语言、JAVA语言等,它们都是静态类型语言,或者叫强类型语言,在变量使用前,都需要声明变量的类型,并且在变量的生命周期内,变量的类型都不能变化,变量仅仅能接收同类型的赋值(相近类型的赋值需要做类型转换),如果不能类型的赋值,将会引发编译错误。

静态类型语言的好处是,在编写程序的时候就知道调用函数的参数类型,编译器、IDE都可以对参数类型进行校验,如果校验不能通过,IDE会直接提示错误。

Python作为动态类型语言不具备上面的特性,但是Python提供了类型注解与提示,可以通过与IDE的交互,让IDE给程序员做类型匹配的校验和提示,注意,这种提示仅仅是IDE的功能,并不影响Python实际的运行。IDE发现类型不匹配,并不会阻止程序执行。

为什么要做类型注解

这个问题的答案跟前面的类对变量、函数的组织等其实是相似的,项目大了,需要工程化开发,也就是很多人很长的时间,写了很多代码,相互之间需要调用函数,不可能都去读代码,需要更快捷的方式去理解,去发现调用的错误。另外,项目的时间可能也会很长,你可能就不记得以前写的函数的参数了,也不可能每次都去重新理解一边代码,编写的时候,也需要IDE帮你尽快、尽早的发现问题,而不是在调试代码的时候再去发现、再去修改。

总之,就是随着项目越来越大,代码可能堆积如山,在这种情况下,如果没有类型注解,我们很容易不记得某一个函数/方法的入参类型是什么,一旦传入了错误类型的参数,再加上python是解释性语言,只有运行时候才能发现问题, 这对大型项目来说是一个巨大的灾难(往往很难定位错误)。

类型注解的作用

自python3.5开始,PEP484为python引入了类型注解(type hints) 机制。 主要作用如下:

  • 类型检查,防止运行时出现参数和返回值类型、变量类型不符合。
  • 作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
  • 该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒。pycharm目前支持typing检查,参数类型错误会黄色提示

因为类型注释的检查是IDE来完成的,所以不同的IDE有不同的方式。PyCharm完全支持类型注解。

类型注解的用法

类型注解主要是对函数/方法的参数类型的注解,也可以在变量被赋值的时候进行注解。

变量/参数的注解

在定义一个变量/参数时,直接在后面 : 类型 就可以给这个变量指定一个类型,后面可以继续写赋值语句 = xx,不写赋值语句也不会出错。

# 声明变量时使用
num: int = 1 #注明num是int类型
str1: str #注明str1是str类型
    

# 函数参数也可以使用
def foo(num: int = 1): #注明num是int类型,缺省值是1
    return num

函数/方法返回值的注解

在函数/方法的冒号之前, -> 可以指定函数/方法的返回值类型,注意,None 是一种类型提示特例

def test(num: int = 1) -> int:  # -> 可以指明函数的返回值类型
    return num


def test(num: int = 1) -> None:  # -> 可以指明函数的返回值类型
    return None

None作为返回值类型,表示函数/方法没有返回值,可以不使用return结束函数/方法。

查看函数/方法的注解

前面我们介绍过,通过自省,可以查看函数/方法的文档、名称等,Python也提供了自省变量来查看函数/方法的注解。

通过 __annotations__ 查看一个函数/方法的注解。

def foo(a: str, b: int = 2) -> None:
    pass

print(foo.__annotations__)
#{'a': <class 'str'>, 'b': <class 'int'>, 'return': None}

容器类型的注解

列表、元组等是容器类型,可以直接使用list、tuple等类型名进行注解,如:

def foo(a: list, b: tuple) -> None:
    pass

如果调用传入的参数类型错误,PyCharm会有黄色的波浪线提示:

python todo注解_参数类型

但是对于容器类型,这样的注解我们是不太满意的,我们希望IDE能帮忙判断容器的元素的类型是否匹配,实际上Python的注解也是可以的,需要在类型后面加上中括号,中括号中标注元素类型,形如“[元素类型]”就可以了。

python todo注解_python_02

注意,元素的类型只能使用中括号括起来,不能使用其他的。

另外,在PyCharm中,列表只能指定一种类型,list[int]可以匹配[1,2,3],而元组可以指定多种类型,tuple[str]不能匹配(‘abc’,’123’),需要列出每个元素的类型,如果跟前面的类型一样,可以使用…来代替。

python todo注解_参数类型_03

dict的元素类型注解,好像在pycharm里没有作用,可能是pycharm的bug:

python todo注解_python_04

各个类型可以进行嵌套,如:

dict[str, list[int]] = {'1': [1,2]}

类型的别名注解

Python也支持给类型取别名,因为我们知道,类型本身也是对象,就把这个对象赋值给一个变量就可以了,例如:

MyType = dict[str, list[int]]  # 给类型取命名
my: MyType = {'counts': [1, 2, 3]}

如上所示,别名也可以直接拿来进行注解。

以上就是“Python进阶(三)类型注解与提示”的全部内容,希望对你有所帮助。