typing类型注解库
简介
动态语言的灵活性使其在做一些工具,脚本时非常方便,但是同时也给大型项目的开发带来了一些麻烦。
自python3.5开始,PEP484为python引入了类型注解(type hints),虽然在pep3107定义了函数注释(function annotation)的语法,但仍然故意留下了一些未定义的行为.现在已经拥有许多对于静态类型的分析的第三方工具,而pep484引入了一个模块来提供这些工具,同时还规定一些不能使用注释(annoation)的情况
#一个典型的函数注释例子,为参数加上了类型
def greeting(name: str) -> str:
return 'Hello ' + name
伴随着python3.6的pep526则更进一步引入了对变量类型的声明,和在以前我们只能在注释中对变量的类型进行说明
# 使用注释来标明变量类型
primes = [] # type:list[int]
captain = ... #type:str
class Starship:
stats = {} #type:Dict[str,int]
primes:List[int] = []
captain:str #Note: no initial value
class Starship:
stats: ClassVar[Dict[str,int]] = {}
typing--对于type hints支持的标准库
typing模块已经被加入标准库的provisional basis中,新的特性可能会增加,如果开发者认为有必要,api也可能会发生改变,即不保证向后兼容性
我们已经在简介中介绍过类型注解,那么除了默认类型的int、str用于类型注解的类型有哪些呢?
typing库便是一个帮助我们实现类型注解的库
类型别名(type alias)
在下面这个例子中,Vector和List[float]可以视为同义词
from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector)->Vector:
return [scalar*num for num in vector]
new_vector = scale(2.0, [1.0, -4.2, 5.4])
类型别名有助于简化一些复杂的类型声明
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:
...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
message: str,
servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
pass
新类型(New Type)
使用NewType来辅助函数创造不同的类型
form typing import NewType
UserId = NewType("UserId", int)
some_id = UserId(524313)
静态类型检查器将将新类型视为原始类型的子类。这对于帮助捕获逻辑错误非常有用
def get_user_name(user_id: UserId) -> str:
pass
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)
你仍然可以使用int类型变量的所有操作来使用UserId类型的变量,但结果返回的都是都是int类型。例如
# output仍然是int类型而不是UserId类型
output = UserId(23413) + UserId(54341)
虽然这无法阻止你使用int类型代替UserId类型,但可以避免你滥用UserId类型
注意,这些检查仅仅被静态检查器强制检查,在运行时Derived = NewType('Derived',base)将派生出一个函数直接返回你传的任何参数,这意味着Derived(some_value)并不会创建任何新类或者创建任何消耗大于普通函数调用消耗的函数
确切地说,这个表达式 some_value is Derived(some_value)
在运行时总是对的。
这也意味着不可能创建派生的子类型,因为它在运行时是一个标识函数,而不是一个实际类型:
from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not typecheck
class AdminUserId(UserId): pass
然而,它可以创建一个新的类型基于衍生的NewType
from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
然后对于ProUserId的类型检查会如预料般工作
Note:回想一下,使用类型别名声明的两个类型是完全一样的,令
Doing = Original
将会使静态类型检查时把Alias等同于Original,这个结论能够帮助你简化复杂的类型声明与Alias不同,NewType声明了另一个的子类,令
Derived = NewType('Derived', Original)
将会使静态类型检查把Derived
看做Original
的子类,这意味着类型Original
不能用于类型Derived
,这有助于使用最小的消耗来防止逻辑错误。
回调(callable)
回调函数可以使用类似Callable[[Arg1Type, Arg2Type],ReturnType]
的类型注释
例如
from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
可以通过对类型提示中的参数列表替换一个文本省略号来声明一个可调用的返回类型,而不指定调用参数,例如 Callable[..., ReturnType]
泛型(Generics)
因为容器中的元素的类型信息由于泛型不同通过一般方式静态推断,因此抽象类被用来拓展表示容器中的元素
from typing import Mapping, Sequence
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
可以通过typing中的TypeVar
将泛型参数化
from typing import Sequence, TypeVar
T = TypeVar('T') # 申明类型变量
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
用户定义泛型类型
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也作为了方法中的参数。
通过Generic基类使用元类(metaclass)定义__getitem__()
使得LoggedVar[t]
是有效类型
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]):
...
每个类型变量的参数必须是不同的
下面是非法的
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]):
...
使用泛型类而不指定类型参数则假定每个位置都是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)
Generic的元类是abc.ABCMeta的子类,泛型类可以是包含抽象方法或属性的ABC类(A generic class can be an ABC by including abstract methods or properties)
同时泛型类也可以含有ABC类的方法而没有元类冲突。
Any
一种特殊的类型是。静态类型检查器将将每个类型视为与任何类型和任何类型兼容,与每个类型兼容。
from typing import Any
a = None # type: Any
a = [] # OK
a = 2 # OK
s = '' # type: str
s = a # OK
def foo(item: Any) -> int:
# Typechecks; 'item' could be any type,
# and that type might have a 'bar' method
item.bar()
...
typing类型注解库的更多相关文章
- typing-python用于类型注解的库
简介 动态语言的灵活性使其在做一些工具,脚本时非常方便,但是同时也给大型项目的开发带来了一些麻烦. 自python3.5开始,PEP484为python引入了类型注解(type hints),虽然在p ...
- Python 3 新特性:类型注解——类似注释吧,反正解释器又不做校验
Python 3 新特性:类型注解 Crossin 上海交通大学 计算机应用技术硕士 95 人赞同了该文章 前几天有同学问到,这个写法是什么意思: def add(x:int, y:int) - ...
- Python Type Hint类型注解
原文地址:https://realpython.com/python-type-checking/ 在本指南中,你将了解Python类型检查.传统上,Python解释器以灵活但隐式的方式处理类型.Py ...
- Java 8新特性探究(二)类型注解和重复注解
本文将介绍java 8的第二个特性:类型注解. 注解大家都知道,从java5开始加入这一特性,发展到现在已然是遍地开花,在很多框架中得到了广泛的使用,用来简化程序中的配置.那充满争议的类型注解究竟是什 ...
- 字符串格式的方法%s、format和python3.6新特性f-string和类型注解
一.%s msg = '我叫%s,今年%s,性别%s' %('帅哥',18,'男') print(msg) # 我叫帅哥,今年18,性别男 二.format # 三种方式: # 第一种:按顺序接收参数 ...
- Python3新特性 类型注解 以及 点点点
Python3新特性 类型注解 以及 点点点 ... Python3 的新特性 Python 是一种动态语言,变量以及函数的参数是 不区分类型 的 在 函数中使用类型注解 相当于 给 形参的 类型 设 ...
- 乐字节-Java8新特性之Base64和重复注解与类型注解
上一篇小乐给大家说了<乐字节-Java8新特性之Date API>,接下来小乐继续给大家说一说Java8新特性之Base64和重复注解与类型注解. 一.Base64 在Java 8中,内置 ...
- Java 8 可重复注解与类型注解
Java 8 可重复注解与类型注解 Java 8 对注解处理提供了两点改进:可重复的注解及可用于类型的注解. // 首先要提供一个容器,MyAnnotation 才能用于可重复注解 @Target({ ...
- Python3.6引入的f-string 与 Python 3的新的特性:类型注解;
f-string 1.介绍 f-string(formatted string literals):格式化字符串常量,是Python3.6新引入的一种字符串格式化方法,使格式化字符串的操作更加简便. ...
随机推荐
- Nginx 高级配置-实现多域名HTTPS
Nginx 高级配置-实现多域名HTTPS 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Nginx支持基于单个IP实现多域名的功能 Nginx支持基于单个IP实现多域名的功能 ...
- 【目录】Jmeter系列
为天地立心,为生民立命.为往圣继绝学,为万世开太平. ---<横渠四句>·张载 Jmeter(一)简介以及环境搭建 Jmeter(二)Jmeter目录介绍 Jmeter(三)Test-Pl ...
- MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)
题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...
- django rest framework 认证组件
1.认证组件 1.认证组件 1.认证组件 1.认证组件
- Android APK开发 Drawable文件夹下的自定义Drawable文件
版本:2018/2/11 Drawable的分类 自定义Drawable SVG矢量图 个人总结的知识点外,部分知识点选自<Android开发艺术探索>-第六章 Drawable 1.Dr ...
- destoon开发笔记-调取资讯标题图
今天刚申请博客园的博客,申请速度挺快的.之前我的文章都是发在自己搭建的博客网站,但是是香港服务器,不想续费了,所以就关闭了.之前的数据也没有了,挺可惜了.不过既然加入博客园的大家庭,我就在这每天记录工 ...
- Kubernetes部署Spring Boot应用
SpringBoot项目 新建springboot项目 @RestController public class HelloWorldController { @RequestMapping(&quo ...
- 洛谷P3835 【模板】可持久化平衡树(FHQ Treap)
题面 传送门 题解 可持久化一下就好了,具体可以看代码 这里有一个小\(trick\)就是我们原本在\(merge\)的时候也要新建节点的,但是我们\(merge\)之前一般已经\(split\)过了 ...
- face-api.js:一个在浏览器中进行人脸识别的 JavaScript 接口
Mark! 本文将为大家介绍一个建立在「tensorflow.js」内核上的 javascript API——「face-api.js」,它实现了三种卷积神经网络架构,用于完成人脸检测.识别和特征点检 ...
- JavaScript的深克隆与浅克隆
JS数据类型分为两类: 基本类型(Number.Boolean.Undefined.Null.String.Symbol(ES6新加,此处不讨论))与引用类型(Object).原始类型存储的是对象的实 ...