Python3中typing模块介绍

x33g5p2x  于2022-01-04 转载在 Python  
字(6.2k)|赞(0)|评价(0)|浏览(215)

    typing.py的源码在:https://github.com/python/cpython/blob/main/Lib/typing.py。此模块为类型提示**(Type Hints)**提供运行时支持(This module provides runtime support for type hints)。从python 3.5版本开始将Typing作为标准库引入。

    python3中增加了Function Annotation(函数注解,能够声明类型)的功能,可以使用类型检查工具如mypy达到类型静态检查的效果。

    类型提示对于运行实际上没有任何影响

    Type aliases:类型别名是通过将类型分配给别名来定义的。类型别名可用于简化复杂类型签名。

# Vector和List[float]将被视为可互换的同义词
Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4]); print(new_vector) # [2.0, -8.4, 10.8]

    NewType:使用NewType辅助类来创建不同的类型。静态类型检查器会将新类型视为原始类型的子类,这有助于捕获逻辑错误。

UserId = NewType('UserId', int) # 实际上UserID就是一个int类型,可以对其像int一样正常操作
some_id = UserId(524313); print(some_id) # 524313

def get_user_name(user_id: UserId) -> str:
    return str(user_id)

user_a = get_user_name(UserId(42351)); print(user_a) # 42351

# 可以对UserId类型的变量执行所有int操作,但结果始终为int类型
output = UserId(23413) + UserId(54341); print(output) # 77754

    Any:是一种特殊的类型。静态类型检查器会将每种类型都视为与Any兼容,同样,Any也与所有类型兼容。可以对Any类型的值执行任何操作或方法调用,并将其分配给任何变量。将Any类型的值分配给更精确的类型(more precise type)时,不会执行类型检查。所有没有返回类型或参数类型的函数都将隐式地默认使用Any。

    Any与object的区别:与Any类似,每个类型都是object的子类型。然而,与Any不同,反过来就不成立了:object不是其它类型的子类型。

    使用object,说明值能以类型安全的方式转为任何类型;使用Any,说明值是动态类型。

a: Any = None
a = [] # OK
a = 2 # OK

s: str = ""
s = a # OK
print(s) # 2

    NoReturn:特殊类型,标记一个函数没有返回值

def stop() -> NoReturn:
    raise RuntimeError('no way')

stop()

    Union:联合类型,Union[X, Y]等价于X|Y,意味着X或Y。使用形如Union[int, str]的形式来定义一个联合体:(1).参数必须是某种类型,且至少有一个;(2).联合类型的联合类型会被展开(flattened);(3).仅有一个参数的联合类型就是该参数自身;(4).冗余的参数会被跳过(skipped);(5).在比较联合类型的时候,参数顺序会被忽略(ignored);(6).不能继承或者实例化一个联合类型;(7).不支持Union[X][Y]这种写法。

# 联合类型的联合类型会被展开(flattened)
Union[Union[int, str], float] == Union[int, str, float]
# 仅有一个参数的联合类型就是该参数自身
Union[int] == int
# 冗余的参数会被跳过(skipped)
Union[int, str, int] == Union[int, str] # == int | str
# 在比较联合类型的时候,参数顺序会被忽略(ignored)
Union[int, str] == Union[str, int]

    Optional:可选类型,Optional[X]等价于X|None,或Union[X, None]。可选类型与含默认值的可选参数不同,含默认值的可选参数不需要在类型注解(type annotation)上添加Optional限定符,因为它仅是可选的。显式应用None值时,不管该参数是否可选,Optional都适用。

# 可选类型与含默认值的可选参数不同,含默认值的可选参数不需要在类型注解(type annotation)上添加Optional限定符,因为它仅是可选的
def foo(arg: int = 0) -> None: ...
# 显式应用None值时,不管该参数是否可选,Optional都适用
def foo(arg: Optional[int] = None) -> None: ...

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

    没有指示可选参数或关键字参数的语法,这种函数类型很少用作回调类型。Callable[…, ReturnType]可用于类型提示一个可调用的接受任意数量的参数并返回ReturnType。一个普通的Callable等价于Callable[…, Any]。

    将其它可调用对象作为参数的可调用对象可能表明它们的参数类型使用typing.ParamSpec相互依赖。此外,如果该可调用对象从其它可调用对象中添加或删除参数,则可以使用typing.Concatenate运算符。

def other_function(x: int, y: float) -> float:
    print(f"x: {x}, y: {y}")
    return y

def any_function(func: Callable[[int, float], float], x: int, y: float) -> float:
    return func(x, y)

any_function(other_function, x=10, y=20)
any_function(other_function, x="abc", y=20) # 注:此条语句可以正常执行,类型提示(type hints)对运行实际上是没有影响的

def get_addr(csdn: str, github: str, port: int=403) -> str:
    return f"csdn: {csdn}, github: {github}, port: {port}"

def get_addr() -> Callable[[str, str, int], str]:
    return get_addr

    Literal:字面类型,可用于向类型检查器指示相应的变量或函数参数与提供的字面量(或多个字面量之一)等效的值。Literal[…]不能创建子类。在运行时,允许将任意值作为Literal[…]的类型参数,但类型检查器可能会对此加以限制。

def validate_simple(data: Any) -> Literal[True]: ... # always returns True

MODE = Literal["r", "rb", "w", "wb"]
def open_helper(file: str, mode: MODE) -> str:
    return file + ":" + mode

print(open_helper("/some/path", "r")) # /some/path:r

    TypeVar:容器中,对象的类型信息不能以Generic(泛型)方式静态推断,因此,抽象基类扩展支持下标(subscription),用于表示容器元素的预期类型。可以使用typing模块中的TypeVar新工厂实现Generic参数化:(1).用户定义的类可以定义为Generic类;(2). Generic类型支持多个类型变量,不过,类型变量可能会受到限制;(3). Generic类型变量的参数都必须是不同的;(4).Generic支持多重继承;(5).从Generic类继承时,可以修复一些类型变量;(6).使用Generic类而不指定类型参数时,每个位置的类型都预设为Any。

T = TypeVar('T') # Declare type variable, Can be anything
# 泛型类型支持多个类型变量,不过,类型变量可能会受到限制
S = TypeVar('S', int, str) # Must be int or str

class StrangePair(Generic[T, S]): ...

# 泛型类型变量的参数都必须是不同的
#class Pair(Generic[T, T]): ... # TypeError: Parameters to Generic[...] must all be unique

length = "5.5"
Length = TypeVar("Length", int, float, None) # Length可以使用int, float或None来表示
def get_length() -> Length:
    return length

print(get_length()) # 5.5

    TypedDict:把类型提示(type hints)添加到字典的特殊构造(special construct)。在运行时,它是一个普通的dict。TypedDict声明一个字典类型,该类型期望它的所有实例都有一组固定的keys,其中每个key都与对应类型的值关联。这种期望不会在运行时检查,而只会由类型检查器强制执行。默认情况下,所有的keys都必须出现在一个TypedDict中,可以通过指定总体(totality)来重写它。

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

    Dict:dict的泛型(generic)版本,用于注解(annotate)返回类型。注解参数时,最好使用抽象集合类型(abstract collection type),例如Mapping。Dict与dict之间没有真正的区别,但是Dict是泛型类型,它允许你指定key和value****的类型,使其更加灵活

def count_words(text: str) -> Dict[str, int]: ...
x: Dict[str, int] = {"beijing", 1}; print(x) # {"beijing", 1}

    Mapping:collections.abc.Mapping的泛型(generic)版本。

def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
    return word_list[word]

def func(m: Mapping[int, str]) -> List[int]:
    return list(m.keys())

print(func({0: "no", 1: "yes"})) # [0, 1]

    List:list的泛型(generic)版本,用于注解(annotate)返回类型。注解参数时,最好使用抽象集合类型(abstract collection type),例如Sequence或Iterable。

T = TypeVar('T', int, float)

def vec2(x: T, y: T) -> List[T]:
    return [x, y]

print(vec2(3, 2)) # [3, 2]

def keep_positives(vector: Sequence[T]) -> List[T]:
    return [item for item in vector if item > 0]

x: List[int] = [1, 2, 3]; print(x) # [1, 2, 3]

    Tuple:元组类型,Tuple[X, Y]是二项的元组类型,第一个元素的类型是X,第二个元素的类型是Y。空元组的类型可以写为Tuple[()]。如Tuple[int, float, str]是由整数、浮点数、字符串组成的三项元组。可用字面省略号(literal ellipsis)指定可变长元组,如Tuple[int, …]。

# 指定所有元素的类型
x: Tuple[int, float, str] = (1, 2.1, "beijing");  print(x) # (1, 2.1, "beijing")
# 可变长度的元组
y: Tuple[int, ...] = (1, 2.1, "beijing"); print(y) # (1, 2.1, "beijing")

    Set:builtins.set的泛型版本,用于注解返回类型。注解参数时,最好使用抽象集合类型,例如AbstractSet。

x: Set[int] = {1, 2, 3}; print(x) # {1, 2, 3}

    AbstractSet:collections.abc.Set的泛型版本。

    Deque:collections.deque的泛型版本。

    Sequence:collections.abc.Sequence的泛型版本。

    Iterable:collections.abc.Iterator的泛型版本。

def func(l: Iterable[int]) -> List[str]:
    return [str(x) for x in l]

print(func(range(1, 5))) # ['1', '2', '3', '4']

    overload:参考:https://blog.csdn.net/fengbingchun/article/details/121959036

    以上内容主要参考:https://docs.python.org/3/library/typing.html

    GitHubhttps://github.com/fengbingchun/Python_Test

相关文章