常用类型提示

  • int,long,float: 整型,长整形,浮点型;
  • bool,str: 布尔型,字符串类型;
  • List, Tuple, Dict, Set:列表,元组,字典, 集合;
  • Iterable,Iterator:可迭代类型,迭代器类型;
  • Generator:生成器类型;

注意:前两行小写的不需要 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)

运行结果:

python 自定义注解函数 python类型注解 知乎_示例代码

类型别名:

        把类型赋给别名,就可以定义类型别名。本例中,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)

运行结果:

python 自定义注解函数 python类型注解 知乎_typing_02

示例代码3:

from typing import Tuple

# 类型别名  --->给类型赋予一个有意义的名称
Vector2D = Tuple[int, int]  # Vector2D 这个名称清晰的表达了这个对象是一个二维的向量。


def foo(vector: Vector2D):
    print(vector)


foo(vector=(1, 2))
foo((1, 2))

运行结果:

python 自定义注解函数 python类型注解 知乎_python_03

示例代码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)

运行结果:

python 自定义注解函数 python类型注解 知乎_示例代码_04

 示例代码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__)  # 查看函数注解信息

运行结果:

python 自定义注解函数 python类型注解 知乎_typing_05

容器类型:

        列表、字典、元组等包含元素的复合类型,用简单的 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 自定义注解函数 python类型注解 知乎_类型注解_06

如果是 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

        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))

运行结果:

python 自定义注解函数 python类型注解 知乎_typing_07

Any:

        如果实在不知道某个类型注解应该怎么写时,这里还有个最后的逃生通道:

示例代码8:

from typing import Any

def foo() -> Any:
    pass

        任何类型都与 Any 兼容。当然如果你把所有的类型都注解为 Any 将毫无意义,因此 Any 应当尽量少使用。

Union:联合类型

        Union[int, str] 表示既可以是 int,也可以是 str 。没有顺序的说法。

Optional:可选类型

        参数可传可不传。注意:Optional[]里面只能写一个数据类型。

Optional[int] = None

Callable:是一个可调用的对象类型

        可调用类型,下标语法(subscription syntax)必须始终与两个值一起使用:参数列表和返回类型。参数列表必须是类型列表或省略号;返回类型必须是单一类型。如:Callable[[int], str]。

查看对象是否是可调用对象:

isinstance(对象, Callable)
Callable type; Callable[[int], str] is a function of (int) -> str.
  • 第一个类型(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))

运行结果:

python 自定义注解函数 python类型注解 知乎_类型注解_08

示例代码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))

运行结果:

python 自定义注解函数 python类型注解 知乎_示例代码_09

类对象调用

示例代码:

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)

运行结果:

python 自定义注解函数 python类型注解 知乎_python 自定义注解函数_10

注意:当类调用本身类型时,需要加上引号,如:’BaseClass',当一个类调用别的类类型时,直接使用类名即可。

参考链接:typing —— 类型注解支持 — Python 3.10.5 文档

参考文章:Python类型注解,你需要知道的都在这里了 - 知乎