简介

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

自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-python用于类型注解的库的更多相关文章

  1. python数字类型之math库使用

    首先我们应当了解什么是math库: math库是python提供的内置数学类函数库,math库不支持复数类型,仅支持整数和浮点数运算.math库一共提供了4个数字常数和44个函数.44个函数共分为4类 ...

  2. typing类型注解库

    简介 动态语言的灵活性使其在做一些工具,脚本时非常方便,但是同时也给大型项目的开发带来了一些麻烦. 自python3.5开始,PEP484为python引入了类型注解(type hints),虽然在p ...

  3. Python Type Hint类型注解

    原文地址:https://realpython.com/python-type-checking/ 在本指南中,你将了解Python类型检查.传统上,Python解释器以灵活但隐式的方式处理类型.Py ...

  4. ​Python 3 新特性:类型注解——类似注释吧,反正解释器又不做校验

    ​Python 3 新特性:类型注解 Crossin ​ 上海交通大学 计算机应用技术硕士 95 人赞同了该文章 前几天有同学问到,这个写法是什么意思: def add(x:int, y:int) - ...

  5. Python中第三方的用于解析HTML的库:BeautifulSoup

    背景 在Python去写爬虫,网页解析等过程中,比如: 如何用Python,C#等语言去实现抓取静态网页+抓取动态网页+模拟登陆网站 常常需要涉及到HTML等网页的解析. 当然,对于简单的HTML中内 ...

  6. Python3.6引入的f-string 与 Python 3的新的特性:类型注解;

    f-string 1.介绍 f-string(formatted string literals):格式化字符串常量,是Python3.6新引入的一种字符串格式化方法,使格式化字符串的操作更加简便. ...

  7. Python入门篇-类型注解

    Python入门篇-类型注解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数定义的弊端 1>.动态语言很灵活,但是这种特性也是弊端 Python是动态语言,变量随时可 ...

  8. python 类型注解

    函数定义的弊端 python 是动态语言,变量随时可以被赋值,且能赋值为不同类型 python 不是静态编译型语言,变量类型是在运行器决定的 动态语言很灵活,但是这种特性也是弊端 def add(x, ...

  9. 量化投资策略:常见的几种Python回测框架(库)

    量化投资策略:常见的几种Python回测框架(库) 原文地址:http://blog.csdn.net/lawme/article/details/51454237 本文章为转载文章.这段时间在研究量 ...

随机推荐

  1. Java基础 TreeSet()来实现数组的【定制排序】 : Comparable接口(自然排序) 或者 Comparator接口 (定制排序)

    笔记: //排序真麻烦!没有C++里的好用又方便!ORZ!ORZ!数组排序还还自己写个TreeSet()和( Comparable接口(自然排序) 或者 Comparator接口 (定制排序))imp ...

  2. ggplot2绘制Excel所有图

    出处:https://brucezhaor.github.io/blog/2016/06/13/excel2ggplot/#%E5%89%8D%E8%A8%80 目录 前言 1.用到的包 2.数据准备 ...

  3. JDK源码那些事儿之我眼中的HashMap

    源码部分从HashMap说起是因为笔者看了很多遍这个类的源码部分,同时感觉网上很多都是粗略的介绍,有些可能还不正确,最后只能自己看源码来验证理解,写下这篇文章一方面是为了促使自己能深入,另一方面也是给 ...

  4. 数组方法push() pop() shift() unshift() splice() sort() reverse() contact()浅拷贝 slice()原数组拷贝

    push() pop() shift() unshift() splice() sort() reverse() 参考资料:https://wangdoc.com/javascript/stdlib/ ...

  5. Spring Bean装配(下)——注解

    @Repository,@Service,@Controller这三个注解是基于component定义的注解 component-scan:组件扫描 base-package:扫描这个下的所有类 &l ...

  6. 2019HDU多校Minimal Power of Prime——分段讨论&&思维

    题目 将 $n$($1 < n \leq 10^{18}$)质因数分解,求质因数幂的最小值. 分析 直接质因数分解,不太行. 可以这样想,对小区间质因数分解,n变小了,再枚举答案. 打印1-10 ...

  7. tap 事件会触发两次问题

    因项目中使用 coffeeScript (http://coffee-script.org/),此处记录下用 coffeeScript 语法解决 tap 事件触发两次的问题. 在 id="b ...

  8. scroll([[data],fn])

    scroll([[data],fn]) 概述 当用户滚动指定的元素时,会发生 scroll 事件. scroll 事件适用于所有可滚动的元素和 window 对象(浏览器窗口).大理石平台支架 参数 ...

  9. ckeditor不能粘贴word的问题如何解决

    自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了.一般情况下我们将Word内容粘贴到Web编辑器(富文本编辑器) ...

  10. iOS测试-如何指标量化app耗电量和性能XCTest Metrics

    对于app端的专项测试,Android端我们可以用adb或者一些三方工具进行(例如itest)进行实时的性能监控,iOS端的话也可以用用一些三方的工具,但是需要嵌入到我们的项目当中,今天来介绍下Xco ...