python Typing模块-类型注解
写在篇前
typing
是python3.5
中开始新增的专用于类型注解(type hints)的模块,为python
程序提供静态类型检查,如下面的greeting
函数规定了参数name
的类型是str
,返回值的类型也是str
。
def greeting(name: str) -> str:return 'Hello ' + name
在实践中,该模块常用的类型有 Any, Union, Tuple, Callable, TypeVar,Optional和Generic等,本篇博客主要依据官方文档以及日常使用经验来探讨一下typing
模块的使用方法以及经验。
注意事项:typing模块虽然已经正式加入到了标准库中,但是如果核心开发者认为有必要的话,api也可能会发生改变,即不保证向后兼容性
Type aliases
简单的类型注解及其形式如开篇例子所示,那么除了默认的int、str
等简单类型,就可以通过typing模块来实现注解。首先,我们可以通过给类型赋予别名,简化类型注释,如下例中的Vector
和List[float]
是等价的。
from typing import List
Vector = List[float]def scale(scalar: float, vector: Vector) -> Vector:return [scalar * num for num in vector]
上面的例子,似乎不能很好的体现类型注释别名的优势,官网还给了另外一个例子,非常生动形象:
from typing import Dict, Tuple, SequenceConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]def broadcast_message(message: str, servers: Sequence[Server]) -> None:passdef broadcast_message2(message: str,servers: Sequence[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:pass
毫无疑问,函数broadcast_message2
的注解明显比broadcast_message
更加简洁清晰。
NewType
可以使用NewType
来创建一个用户自定义类型,如:
from typing import NewTypeUserId = NewType("UserId", int)
def get_user_name(user_id: UserId) -> str:pass# 可以通过类型检查
user_a = get_user_name(UserId(42351))
# 不能够通过类型检查
user_b = get_user_name(-1)
NewType
的实现方式很简单,在运行时,NewType(name, tp)
返回一个函数,这个函数返回其原本的值。静态类型检查器会将新类型看作是原始类型的一个子类。
# NewType实现代码
def NewType(name, tp):def new_type(x):return xnew_type.__name__ = namenew_type.__supertype__ = tpreturn new_type
因为NewType
被看做原始类型的子类,因此在新类型上你可以进行原始类型允许的操作,且结果的类型是原始类型,看起来是不是很神奇,甚至有点绕!其实关键还是要理解其原理,举两个例子:
实例1
>>> user_id_1 = UserId(23) >>> user_id_2 = UserId(46) >>> user_id_1 + user_id_2 69
实例2
# 请和NewType第一个例子对比 def get_num(num: int) -> int:return num# 可以通过类型检查 get_num(1)user_id: UserId = UserId(23) # 可以通过类型检查 get_num(user_id)
请注意,这些检查仅会被静态类型检查程序强制执行。在运行时,Derived = NewType('Derived',Base)
将 Derived
一个函数,该函数立即返回传递给它的任何参数。这意味着表达式 Derived(some_value)
不会创建一个新的类或引入任何超出常规函数调用的开销。更确切地说,表达式 some_value is Derived(some_value)
在运行时总是为真。这也意味着无法创建 Derived
的子类型,因为它是运行时的标识函数,而不是实际的类型。
Callable
回调函数可以使用类似Callable[[Arg1Type, Arg2Type],ReturnType]
的类型注释,这个比较简单,例子如下,如果只指定回调函数的返回值类型,则可以使用Callable[..., ReturnType]
的形式:
from typing import Callabledef async_query(on_success: Callable[[int], None],on_error: Callable[[int, Exception], None]) -> None:pass
Generics
由于无法以通用的方式静态推断有关保存在容器(list set tuple
)中对象的类型信息,因此抽象类被用来拓展表示容器中的元素。如下面子里中,使用基类Employee
来扩展其可能得子类如 Sub1_Employee
、Sub2_Employee
等。但是其局限性明显,所以我们需要引入泛型(generics)。
from typing import Mapping, Sequencedef notify_by_email(employees: Sequence[Employee],overrides: Mapping[str, str]) -> None:pass
可以通过typing中的TypeVar
将泛型参数化,如:
from typing import Sequence, TypeVarT = TypeVar('T') # Can be anything
A = TypeVar('A', str, bytes) # Must be str or bytesdef first(l: Sequence[T]) -> T: # Generic functionreturn l[0]
User-defined generic types
可以将用户字定义的类定义为泛型类:
from typing import TypeVar, Generic
from logging import LoggerT = TypeVar('T')class LoggedVar(Generic[T]):def __init__(self, value: T, name: str, logger: Logger) -> None:self.name = nameself.logger = loggerself.value = valuedef set(self, new: T) -> None:self.log('Set ' + repr(self.value))self.value = newdef get(self) -> T:self.log('Get ' + repr(self.value))return self.valuedef log(self, message: str) -> None:self.logger.info('%s: %s', self.name, message)
Generic[T]
作为基类定义了类 LoggedVar
采用单个类型参数 T
。这也使得 T
作为类体内的一个类型有效。通过Generic基类使用元类(metaclass)定义__getitem__()
使得LoggedVar[t]
是有效类型:
from typing import Iterabledef zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:for var in vars:var.set(0)
泛型类型可以有任意数量的类型变量,并且类型变量可能会受到限制:
from typing import TypeVar, GenericT = TypeVar('T')
S = TypeVar('S', int, str)class StrangePair(Generic[T, S]):pass
Any Type
Any
是一种特殊的类型,静态类型检查器视Any
与任何类型兼容,任何类型与Any
兼容。
def foo(item: Any) -> int:item.bar()
写在篇后
在实际使用中, Any, Union, Tuple, List, Sequence, Mapping, Callable, TypeVar,Optional, Generic
等的使用频率比较高,其中Union、Optional、Sequence、Mapping
非常有用,注意掌握。
Union
即并集,所以
Union[X, Y]
意思是要么X类型、要么Y类型Optional
Optional[X]
与Union[X, None]
,即它默认允许None类型Sequence
即序列,需要注意的是,
List
一般用来标注返回值;Sequence、Iterable
用来标注参数类型Mapping
即字典,需要注意的是,
Dict
一般用来标注返回值;Mapping
用来标注参数类型
贴一段类型标注的实例代码,是不是让人一目了然,不需要看具体代码逻辑就知道参数类型以及如何调用呢?
def __init__(self,X: Optional[Union[np.ndarray, sparse.spmatrix, pd.DataFrame]] = None,obs: Optional[Union[pd.DataFrame, Mapping[str, Iterable[Any]]]] = None,var: Optional[Union[pd.DataFrame, Mapping[str, Iterable[Any]]]] = None,uns: Optional[Mapping[str, Any]] = None,obsm: Optional[Union[np.ndarray, Mapping[str, Sequence[Any]]]] = None,varm: Optional[Union[np.ndarray, Mapping[str, Sequence[Any]]]] = None,layers: Optional[Mapping[str, Union[np.ndarray, sparse.spmatrix]]] = None,raw: Optional[Raw] = None,dtype: Union[np.dtype, str] = 'float32',shape: Optional[Tuple[int, int]] = None,filename: Optional[PathLike] = None,filemode: Optional[str] = None,asview: bool = False,*, oidx: Index = None, vidx: Index = None):
类型标注可以使程序的维护性、使用性更高,这一点非常重要;另外,许多IDE配合类型标注可以增强智能提示功能,加快编码速度,提高效率,我们何乐而不为呢?
python Typing模块-类型注解相关推荐
- [转]关于Python里的类型注解
我们知道 Python 是一种动态语言,在声明一个变量时我们不需要显式地声明它的类型,例如下面的例子: a = 2print('1 + a =', 1 + a) print('1 + a =', 1 ...
- python typing optional_python类型检测最终指南--Typing模块的使用
正文共:30429 字 预计阅读时间:76分钟 原文链接:https://realpython.com/python-type-checking/ 作者:Geir Arne Hjelle 译者:陈祥安 ...
- Python Type Hint类型注解
原文地址:https://realpython.com/python-type-checking/ 在本指南中,你将了解Python类型检查.传统上,Python解释器以灵活但隐式的方式处理类型.Py ...
- python中函数type可以测试对象类型_python类型检测最终指南--Typing模块的使用
正文共:30429 字 预计阅读时间:76分钟 原文链接:https://realpython.com/python-type-checking/ 作者:Geir Arne Hjelle 译者:陈祥安 ...
- python 类型注解 list_Python 类型注解
说明 Python 教程正在编写中,欢迎大家加微信 sinbam 提供意见.建议.纠错.催更. 简单说,Python 类型注解功能可以让我们的代码更加易读,从而达到编写更加健壮的代码目标.类型注解又叫 ...
- 《流畅的Python第二版》读书笔记——函数中的类型注解
引言 这是<流畅的Python第二版>抢先版的读书笔记.Python版本暂时用的是python3.10.为了使开发更简单.快捷,本文使用了JupyterLab. 本章关注于Python在函 ...
- Python 3 新特性:类型注解——类似注释吧,反正解释器又不做校验
Python 3 新特性:类型注解 Crossin 上海交通大学 计算机应用技术硕士 95 人赞同了该文章 前几天有同学问到,这个写法是什么意思: def add(x:int, y:int) - ...
- 【Python教程】typing模块的作用-提高代码健壮性
typing模块的作用: 类型检查,防止运行时出现参数和返回值类型不符合. 作为开发文档附加说明,方便使用者调用时传入和返回参数类型. 该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒. ...
- Python 3 新特性:类型注解
Python 3 新特性:类型注解 之前也看到这种写法,有人疑惑这个写法是什么意思: def add(x:int, y:int) -> int:return x + y 我们知道 Python ...
最新文章
- Android Binder设计与实现 – 设计篇
- 名校 Stanford
- HttpUrlConnection get和post简单实现(疑惑解决)
- Linux——进程系列知识详述(操作系统、PCB进程控制块、查看进程状态等)
- 微软2021校园招聘正式启动
- VSX-5 VSXMusic 编码听音乐
- 时间轮算法解析(Netty HashedWheelTimer源码解读)
- 状态压缩 + 暴力 HDOJ 4770 Lights Against Dudely
- wpf notifyIcon
- 【numpy】numpy.zeros()函数
- matlab gui 图像增强,基于MATLAB GUI的图像增强技术的实现
- zabbix登陆拒绝报没有权限
- gitblit如何迁移入gitlab合并迁移_最新gitlab备份迁移方案
- 中小企业网络推广方案
- flutter 截图 截长图 滚动截图 保存到手机
- 2021-2022 ACM-ICPC Brazil Subregional Programming Contest C Creating Multiples
- SDUT最短路径问题 1867————最短路
- 网易云催生云计算更多可能性
- PAT 乙级 1040 有几个PAT (25分)
- SCI论文写作的学习与总结
热门文章
- Netty之自定义编码器MessageToMessageEncoder类
- 简洁易懂:c:out标签详解
- 一条SQL更新语句是如何执行的?
- 详细图文演示——排除启动类故障以及Linux操作系统引导、运行级别和优化启动等相关知识
- python 写txt 换行_python中写入txt文件需要换行,以及\r 和\n
- jsp页面实现打印 .
- Android下检测网络连接 3G WIFI
- 公平锁非公平锁的实际使用_3. redisson源码公平锁之队列重排序
- python的字符串_百度资讯搜索_python的字符串
- c++ 使用nacos_Nacos配置的多环境管理