Python是一门弱类型的语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果,就不得不去阅读代码的具体内容,降低了阅读的速度,typing模块可以很好的解决这个问题
自python3.5开始,PEP484为python引入了类型注解(type hints),typing模块的作用:
使用方式,函数接受并返回一个字符串,注释像下面这样:
def greeting(name: str) -> str:
return 'Hello ' + name
在函数 greeting 中,参数 name 预期是 str 类型,并且返回 str 类型。子类型允许作为参数。
最新支持方式,请查看官方中文文档:https://docs.python.org/zh-cn/3.6/library/typing.html
1、使用or关键字或者Union表示多种类型。 List[int or str] <=> Union[int, str]。
from typing import List, Union
# 等价于 def func(a: int, string: str) -> Union[int, str] :
def func(a: int, string: str) -> List[int or str]:
list1 = []
list1.append(a)
list1.append(string)
return list1
print(func(88,"999"))
2、Any类型使用,是代码风格保持一致
def add(a):
return a + 1
# 等价于=>
def add(a: Any) -> Any:
return a + 1
3、NoReturn,当一个方法没有返回结果时,为了注解它的返回类型,我们可以将其注解为 NoReturn。
def hello() -> NoReturn:
print('hello')
类型别名通过将类型分配给别名来定义。在这个例子中, Vector 和 List[float] 将被视为可互换的同义词:
from typing import List
Vector = List[float] # Vector 和 List[float] 将被视为可互换的同义词:
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
类型别名可进行嵌套,用于简化复杂类型签名。例如:
from typing import Dict, Tuple, List
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: List[Server]) -> None:
...
使用 NewType() 辅助函数创建不同的类型:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
静态类型检查器会将新类型视为它是原始类型的子类。这对于帮助捕捉逻辑错误非常有用:
def get_user_name(user_id: UserId) -> str:
...
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)
仍然可以对 UserId 类型的变量执行所有的 int 支持的操作,但结果将始终为 int 类型。这可以让你在需要 int 的地方传入 UserId,但会阻止你以无效的方式无意中创建 UserId:
# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)
Callable,可调用类型,它通常用来注解一个方法.Callable 在声明的时候需要使用 Callable[[Arg1Type, Arg2Type, …], ReturnType] 这样的类型注解,将参数类型和返回值类型都要注解出来.
def date(year: int, month: int, day: int) -> str:
return f'{year}-{month}-{day}'
def get_date_fn() -> Callable[[int, int, int], str]:
return date
用户定义的类可以定义为泛型类。
from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
Generic[T] 作为基类定义了类 LoggedVar 采用单个类型参数 T。这也使得 T 作为类体内的一个类型有效。
The Generic base class uses a metaclass that defines __getitem__() so that LoggedVar[t] is valid as a type:
from typing import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
泛型类型可以有任意数量的类型变量,并且类型变量可能会受到限制:
from typing import TypeVar, Generic
...
T = TypeVar('T')
S = TypeVar('S', int, str)
class StrangePair(Generic[T, S]):
...
Generic 每个参数的类型变量必须是不同的。这是无效的:
from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
可以对 Generic 使用多重继承:
from typing import TypeVar, Generic, Sized
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
...
从泛型类继承时,某些类型变量可能是固定的:
from typing import TypeVar, Mapping
T = TypeVar('T')
class MyDict(Mapping[str, T]):
...
在这种情况下,MyDict 只有一个参数,T。
在不指定类型参数的情况下使用泛型类别会为每个位置假设 Any。在下面的例子中,MyIterable 不是泛型,但是隐式继承自 Iterable[Any]:
from typing import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
用户定义的通用类型别名也受支持。例子:
from typing import TypeVar, Iterable, Tuple, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]
# Return type here is same as Union[Iterable[str], int]
def response(query: str) -> Response[str]:
...
T = TypeVar('T', int, float, complex)
Vec = Iterable[Tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[Tuple[T, T]]
return sum(x*y for x, y in v)
The metaclass used by Generic is a subclass of abc.ABCMeta. A generic class can be an ABC by including abstract methods or properties, and generic classes can also have ABCs as base classes without a metaclass conflict. Generic metaclasses are not supported. The outcome of parameterizing generics is cached, and most types in the typing module are hashable and comparable for equality.
传送门:python系列文章目录及学习资源汇总
参考文章:
1、https://www.cnblogs.com/angelyan/p/11121859.html
2、https://blog.csdn.net/qq_21127151/article/details/104666542