Python是一种弱类型的解释性语言,以前在使用的时候往往也只是当作弱类型来使用。在开发小型系统的时候,弱类型也没什么问题,但是系统稍微复杂点,维护就可能会变成一个大坑。
不过自从Python3.6之后,已经加入了类型提示的功能,现在主流的版本也是3.8了,是时候该上马类型编程了。
一个简单的例子
先上一碟小菜:
def hello(name: str="world") -> str:
msg = f"hello {name}"
return msg
print(hello("deeao"))不过这真的只是一个类型提示,随便传入一个值都不会进行参数校验:
print(hello(30))
print(hello([30]))这也不会报错,这特性也挺让人失望的。
更复杂的类型
简单的类型,我们有bool,int,float,str等,也有复杂一点的tuple,list,set,dict等,不过这些几个复杂一点的类型的定义并不是太清晰,例如list,只知道是一个列表,却没有定义列表元素的类型。我们需要借助typing来定义更加清晰的数据结构:
from typing import Dict, List, Tuple, Set, Optional
# 定义向量类型,元素为float的列表
Vector = List[float]
# key和value的类型都是str
ConnectionOptions = Dict[str, str]
# 包含str和int两种类型的列表
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]
def say_hi(name: Optional[str] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")官方文档:https://docs.python.org/zh-cn/3/library/typing.html

特殊类型与特殊形式
typing.TupleTuple[X, Y] 是二项元组类型,第一个元素的类型是 X,第二个元素的类型是 Y。空元组的类型可写为 Tuple[()]。
例:Tuple[T1, T2] 是二项元组,类型变量分别为 T1 和 T2。Tuple[int, float, str] 是由整数、浮点数、字符串组成的三项元组。
可用省略号字面量指定同质变长元组,例如,Tuple[int, ...] 。Tuple 与 Tuple[Any, ...] 等价,也与 tuple 等价。typing.UnionUnion[X, Y] 的意思是,非 X 即 Y。
可用 Union[int, str] 等形式定义联合类型。具体如下:Union[X][Y] 这种写法。Optional[X] 是 Union[X, None] 的缩写。typing.AnyAny 兼容。Any 与所有类型都兼容。typing.NoReturntyping.NamedTuplecollections.namedtuple() 的类型版本。
用法:
class Employee(NamedTuple): name: str id: int
相当于:
Employee = collections.namedtuple('Employee', ['name', 'id'])
为字段提供默认值,要在类体内赋值:
class Employee(NamedTuple): name: str id: int = 3 employee = Employee('Guido') assert employee.id == 3
带默认值的字段必须在不带默认值的字段后面。typing.NewType(name, tp)typing.TypedDict(dict)dict。
TypedDict 声明一个字典类型,该类型预期所有实例都具有一组键集,其中,每个键都与对应类型的值关联。运行时不检查此预期,而是由类型检查器强制执行。用法如下:
class Point2D(TypedDict): x: int y: int label: str a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
用于内省的类型信息可通过 Point2D.__annotations__ 和 Point2D.__total__ 访问。FastAPI中的应用
FastAPI中的接口参数是有类型校验的,我猜应该是使用装饰器内使用反射实现的。
关于Python类型的小结
Python虽然有了类型提示,可依然是弱类型,仅仅是作为提示作用(不知道以后的版本会不会继续增强),跟强类型还是差了很远。
不过聊胜于无吧,能写出清晰的代码也是大功一件,而且各种编辑器的代码提示也得依赖类型提示来实现代码补全。
使用python开发系统,应该强制使用清晰的变量类型定义,即使小系统,也应该这样。(有些系统可能开始开发的时候,是个小系统,但是开发过程中,代码越来越多,就变成了一个复杂系统)