Python标准库之typing的用法(类型标注)


Posted in Python onJune 02, 2021

PEP 3107引入了功能注释的语法,PEP 484 加入了类型检查

标准库 typing 为类型提示指定的运行时提供支持。

示例:

def f(a: str, b:int) -> str:
    return a * b

Python标准库之typing的用法(类型标注)

如果实参不是预期的类型:

Python标准库之typing的用法(类型标注)

但是,Python运行时不强制执行函数和变量类型注释。使用类型检查器,IDE,lint等才能帮助代码进行强制类型检查。

使用NewType 创建类型

NewType() 是一个辅助函数,用于向类型检查器指示不同的类型,在运行时,它返回一个函数,该函数返回其参数。

import typing
Id = typing.NewType("Id", int)
a = Id(2020)

使用 NewType() 创建的类型会被类型检查器视为它的原始类型的子类。

回调(Callable)

将回调函数类型标注为 Callable[[Arg1Type, Arg2Type], ReturnType]。

from typing import Callable
def f(a: int) -> str:
    return str(a)
def callback(a: int, func: Callable[[int], str]) -> str:
    return func(a)
print(callback(1, f))

泛型

为容器元素添加预期的类型

from typing import Mapping
a: Mapping[str, str]

Python标准库之typing的用法(类型标注)

通过 TypeVar 进行参数化来约束一个类型集合:

from typing import TypeVar
T = TypeVar('T') # 可以是任何东西。
A = TypeVar('A', str, bytes) # 必须是 str 或 bytes

Python标准库之typing的用法(类型标注)

使用 TypeVar 约束一个类型集合,但不允许单个约束

例如:

T = TypeVar('T', str)

这样会抛出一个异常 TypeError: A single constraint is not allowed

typing 包含的类型

AbstractSet = typing.AbstractSet
Any = typing.Any
AnyStr = ~AnyStr
AsyncContextManager = typing.AbstractAsyncContextManager
AsyncGenerator = typing.AsyncGenerator
AsyncIterable = typing.AsyncIterable
AsyncIterator = typing.AsyncIterator
Awaitable = typing.Awaitable
ByteString = typing.ByteString
Callable = typing.Callable
ClassVar = typing.ClassVar
Collection = typing.Collection
Container = typing.Container
ContextManager = typing.AbstractContextManager
Coroutine = typing.Coroutine
Counter = typing.Counter
DefaultDict = typing.DefaultDict
Deque = typing.Deque
Dict = typing.Dict
FrozenSet = typing.FrozenSet
Generator = typing.Generator
Hashable = typing.Hashable
ItemsView = typing.ItemsView
Iterable = typing.Iterable
Iterator = typing.Iterator
KeysView = typing.KeysView
List = typing.List
Mapping = typing.Mapping
MappingView = typing.MappingView
MutableMapping = typing.MutableMapping
MutableSequence = typing.MutableSequence
MutableSet = typing.MutableSet
NoReturn = typing.NoReturn
Optional = typing.Optional
Reversible = typing.Reversible
Sequence = typing.Sequence
Set = typing.Set
Sized = typing.Sized
TYPE_CHECKING = False
Tuple = typing.Tuple
Type = typing.Type
Union = typing.Union
ValuesView = typing.ValuesView

typing-python用于类型注解的库

简介

动态语言的灵活性使其在做一些工具,脚本时非常方便,但是同时也给大型项目的开发带来了一些麻烦。

自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()
    ...

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python实现一个简单的能够上传下载的HTTP服务器
May 05 Python
Django查找网站项目根目录和对正则表达式的支持
Jul 15 Python
Python、PyCharm安装及使用方法(Mac版)详解
Apr 28 Python
python使用TensorFlow进行图像处理的方法
Feb 28 Python
tensorflow: 查看 tensor详细数值方法
Jun 13 Python
python实现基于信息增益的决策树归纳
Dec 18 Python
pyshp创建shp点文件的方法
Dec 31 Python
基于Python检测动态物体颜色过程解析
Dec 04 Python
Python数据存储之 h5py详解
Dec 26 Python
利用Python如何实时检测自身内存占用
May 09 Python
如何真正的了解python装饰器
Aug 14 Python
Python unittest如何生成HTMLTestRunner模块
Sep 08 Python
只用50行Python代码爬取网络美女高清图片
这样写python注释让代码更加的优雅
Jun 02 #Python
上帝为你开了一扇窗之Tkinter常用函数详解
只用20行Python代码实现屏幕录制功能
TensorFlow中tf.batch_matmul()的用法
Jun 02 #Python
pytorch 运行一段时间后出现GPU OOM的问题
Jun 02 #Python
python flask开发的简单基金查询工具
You might like
php快速url重写 更新版[需php 5.30以上]
2010/04/20 PHP
PHP FTP操作类代码( 上传、拷贝、移动、删除文件/创建目录)
2014/05/10 PHP
PHP获取客户端真实IP地址的5种情况分析和实现代码
2014/07/08 PHP
php+xml实现在线英文词典查询的方法
2015/01/23 PHP
php按单词截取字符串的方法
2015/04/07 PHP
使用Huagepage和PGO来提升PHP7的执行性能
2015/11/30 PHP
php无限级分类实现评论及回复功能
2019/02/18 PHP
今天是星期几的4种JS代码写法
2013/09/17 Javascript
JS判断、校验MAC地址的2个实例
2014/05/05 Javascript
JQuery调用WebServices的方法和4个实例
2014/05/06 Javascript
Jquery树插件zTree用法入门教程
2015/02/17 Javascript
基于jquery实现简单的分页控件
2016/03/17 Javascript
jQuery简单实现上下,左右滑动的方法
2016/06/01 Javascript
jquery 仿锚点跳转到页面指定位置的实例
2017/02/14 Javascript
bootstrap table表格插件使用详解
2017/05/08 Javascript
原生JS实现自定义滚动条效果
2020/10/27 Javascript
JavaScript 保护变量不被随意修改的实现代码
2017/09/27 Javascript
vue监听对象及对象属性问题
2018/08/20 Javascript
vue mounted 调用两次的完美解决办法
2018/10/29 Javascript
vue 组件内获取actions的response方式
2019/11/08 Javascript
vue 递归组件的简单使用示例
2021/01/14 Vue.js
简单介绍Python中的len()函数的使用
2015/04/07 Python
Python实现以时间换空间的缓存替换算法
2016/02/19 Python
python中利用await关键字如何等待Future对象完成详解
2017/09/07 Python
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
简单了解python的break、continue、pass
2019/07/08 Python
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
JMS中Topic和Queue有什么区别
2013/05/15 面试题
与UNIX有关的几个名词
2015/09/17 面试题
商场端午节活动方案
2014/01/29 职场文书
吸烟检讨书2000字
2014/02/13 职场文书
“学雷锋活动月”总结
2014/03/09 职场文书
贷款担保书范文
2014/05/13 职场文书
党员教师四风自我剖析材料
2014/09/30 职场文书
工程部文员岗位职责
2015/02/04 职场文书
我们的节日中秋节活动总结
2015/03/23 职场文书