注意:前两行小写的不需要 import,后面三行都需要通过 typing 模块 import
注意:当List[str]时里面有多个时只有写一个即可,当为Tuple[str, ...]里面有多个时需要添加 ...
注解:
Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。
在定义函数时使用“注解”的形式来标注形参和返回值的类型,但这种注解的形式并不会对形参进行任何约束和检查,在实际调用函数时,即使实参不符合形参的类型标注,一样能够正常传递。
Python 中几种基本的变量类型都得到了支持:
a: int = 3
b: float = 3.14
c: str = 'abc'
d: bool = False
下面的函数接收与返回的都是字符串,注解方式如下:
示例代码1:
"""
greeting 函数中,参数 name 的类型是 str,返回类型也是 str。子类型也可以当作参数。
"""
def greeting(name: str) -> str:
return 'Hello ' + name
a = greeting('dgw')
print(a)
运行结果:
类型别名:
把类型赋给别名,就可以定义类型别名。本例中,Vector
和 list()
相同,可互换:
示例代码2:
Vector = list()
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])
print(new_vector)
运行结果:
示例代码3:
from typing import Tuple
# 类型别名 --->给类型赋予一个有意义的名称
Vector2D = Tuple[int, int] # Vector2D 这个名称清晰的表达了这个对象是一个二维的向量。
def foo(vector: Vector2D):
print(vector)
foo(vector=(1, 2))
foo((1, 2))
运行结果:
示例代码4:【与类型别名有点类似的,是用 NewType
创建自定义类型,但不同的是 NewType
创建了原始类型的“子类”】
from typing import Tuple
from typing import NewType
# 类型别名 --->给类型赋予一个有意义的名称
Vector2D = Tuple[int, int] # Vector2D 这个名称清晰的表达了这个对象是一个二维的向量。
def foo(vector: Vector2D):
print(vector)
# 创建新类型
Vector3D = NewType('Vector3D', Tuple[int, int, int])
def bar(vector: Vector3D):
print(vector)
# 类型检查成功
# 类型别名和原始类型是等价的
foo(vector=(1, 2))
# 类型检查失败
# NewType创建的是原始类型的“子类”
bar(vector=(1, 2, 3))
# 类型检查成功
# 传入参数必须是 Vector3D 的“实例”
v_3d = Vector3D((4, 5, 6))
bar(vector=v_3d)
运行结果:
示例代码5:
def demo(name: str = '名字', age: int = 31) -> "str":
print("函数注解", demo.__annotations__) # 查看函数注解信息
print("打印实参", name, age)
print(type(name), type(age))
ret = "name:" + name + ', age:' + str(age)
return ret
a = demo()
print(a)
print('*' * 100)
b = demo('张三')
print(b)
print('*' * 100)
c = demo('张三', 25)
print(c)
print('*' * 100)
print("函数注解", demo.__annotations__) # 查看函数注解信息
运行结果:
容器类型:
列表、字典、元组等包含元素的复合类型,用简单的 list,dict,tuple 不能够明确说明内部元素的具体类型。
因此要用到 typing
模块提供的复合注解功能:
示例代码6:
from typing import List, Dict, Tuple
# 参数1: 元素为 int 的列表
# 参数2: 键为字符串,值为 int 的字典
# 返回值: 包含两个元素的元组
def mix(scores: List[int], ages: Dict[str, int]) -> Tuple[int, int]:
print(scores)
print(ages)
return (0, 0)
a = mix(99, ('zhangsan', 25))
print(a)
运行结果:
如果是 Python 3.9+ 版本,甚至连 typing
模块都不需要了,内置的容器类型就支持了复合注解:
def mix(scores: list[int], ages: dict[str, int]) -> tuple[int, int]:
return (0, 0)
在某些情况下,不需要严格区分参数到底是列表还是元组(这种情况还蛮多的)。这时候就可以将它们的特征抽象为更泛化的类型(泛型),比如 Sequence(序列)。
示例代码7:
# Python 3.8 之前的版本
from typing import Sequence as Seq1
def foo(seq: Seq1[str]):
for item in seq:
print(item)
foo([1, 2, 3])
# Python 3.9+ 也可以这么写
from collections.abc import Sequence as Seq2
def bar(seq: Seq2[str]):
for item in seq:
print(item)
bar([11, 22, 33])
上述代码中函数的参数不对容器的类型做具体要求,只要它是个序列(比如列表和元组)就可以。
dict的泛型(generic)版本,用于注解(annotate)返回类型。注解参数时,最好使用抽象集合类型(abstract collection type)。
Dict与dict之间没有真正的区别,但是Dict是泛型类型,它允许你指定key和value的类型,使其更加灵活。
示例代码:
from typing import Dict
def func(x: str) -> Dict[str, int]:
data: Dict[str, int] = {x: 6}
return data
ret = func('num')
print(ret, type(ret))
运行结果:
如果实在不知道某个类型注解应该怎么写时,这里还有个最后的逃生通道:
示例代码8:
from typing import Any
def foo() -> Any:
pass
任何类型都与 Any
兼容。当然如果你把所有的类型都注解为 Any
将毫无意义,因此 Any
应当尽量少使用。
Union[int, str] 表示既可以是 int,也可以是 str 。没有顺序的说法。
参数可传可不传。注意:Optional[]里面只能写一个数据类型。
Optional[int] = None
可调用类型,下标语法(subscription syntax)必须始终与两个值一起使用:参数列表和返回类型。参数列表必须是类型列表或省略号;返回类型必须是单一类型。如:Callable[[int], str]。
查看对象是否是可调用对象:
isinstance(对象, Callable)
Callable type; Callable[[int], str] is a function of (int) -> str.
from typing import Callable
def func(x: Callable[[str], None]):
pass
示例代码1:
from typing import Callable
def base_func(x: int, y: float) -> float:
return float(x) + y
def any_func(func: Callable[[int, float], float], x: int, y: float) -> float:
return func(x, y)
ret = any_func(base_func, x=10, y=3.1)
print(ret, type(ret))
运行结果:
示例代码2:
from typing import Callable
def base_func(x: int, y: float, z: str) -> str:
return str(x) + str(y) + z
def func1(func: Callable[[int, float, str], str], s: str) -> str:
ret = func(3, 3.6, 'aa') + s
return ret
def func2(func: Callable, s: str) -> str:
ret = func(3, 3.6, 'aa') + s
return ret
ret1 = func1(base_func, 'bb')
print(ret1, type(ret1))
ret2 = func2(base_func, 'cc')
print(ret2, type(ret2))
运行结果:
示例代码:
class BaseClass(object):
name = 'dgw'
age = 26
def base_func(self, _class: 'BaseClass', x: str) -> str:
res = str(_class) + x
return res
class SubClass(BaseClass):
def func(self, param: BaseClass) -> str:
name = param.name
age = param.age
return name + str(age)
obj = BaseClass()
ret = obj.base_func(obj, 'xyz')
print(ret, type(ret))
obj2 = SubClass()
ret2 = obj2.func(obj)
print(ret2)
运行结果:
注意:当类调用本身类型时,需要加上引号,如:’BaseClass',当一个类调用别的类类型时,直接使用类名即可。
参考链接:typing —— 类型注解支持 — Python 3.10.5 文档
参考文章:Python类型注解,你需要知道的都在这里了 - 知乎
Python3中typing模块介绍_fengbingchun的博客-CSDN博客_python typing模块