python mypy类型检查_Python的类型标注与检查

Python作为一个动态类型语言,支持Subtyping和Duck Typing,一些Lint工具可以对Python代码静态进行类型

检查来提高程序质量,还有工具可以支持类型标注和检查,并编译代码以提升性能。Python 3.5又引入了

Type Hints机制来提供统一的类型标注协议。

__class__ and isinstance

Python中,判断一个对象是否是某个类的实例的做法:

判断直接实例使用a.__class__ is A

判断间接实例使用isinstance(a, A)

__class__可以用来获取一个对象的类对象,is用于比较是否是内存中的同一个对象。isinstance判断

给出的对象是否是给出的类的直接或间接实例类型。举例:

In []: class A: pass

In []: class B(A): pass

In []: b = B()

In []: b.__class__ is B

Out[]: True

In []: b.__class__ is A

Out[]: False

In []: isinstance(b, B)

Out[]: True

In []: isinstance(b, A)

Out[]: True

Duck Typing

Duck Typing,鸭子类型,是动态类型的一种实现风格,指的是一个对象的语义不取决于其继承

自特定的类或实现特定的接口,而是关注这个对象有哪些可以被调用的方法和可以被访问的属性。

当被调用的方法或被访问的属性不存在时,会产生一个运行时错误。Python使用了Duck Typing

来实现多态(Run Time Polymorphism)的能力。示例:

class A:

def f(): pass

def g(): pass

class B:

def g(): pass

def h(): pass

def func(duck):

g()

Duck Typing放弃了任何类型检查,完全没有语言本身的机制来检查,这种方式非常灵活,

完全依靠程序员来通过注释、文档、测试来强制约束。除了Python之外,Java(通过reflection)、

Javascript,Common Lisp等编程语言也支持Duck Typing。

Type Hints

PEP 482、PEP 483和PEP 484这三篇Proposal描述了Python 3.5引入的Type Hints机制。已经有mypy、

Reticulated Python和numba等实现了一定程度的静态类型检查,PyCharm这类IDE也通过类型推导

和检查机制来静态检查代码中的错误以及给出改进建议。其他的一些动态类型语言如PHP、TypeScript

等也引入了Type Hints来进行运行时的类型推导和检查。

值得注意的是,Type Hints只是提供了一个统一的类型标注的协议,而并没有提供类型检查机制。

def greeting(name: str) -> str:

return 1

if __name__ == '__main__':

print(greeting(1))

很明显这段代码中函数的实际返回值类型标注不符,且调用函数时参数类型也与标注不符,但仍然

能正常运行。

早在2006年,PEP 3107 Function Annotations就已经允许对函数的参数和返回值进行类型和注释

的标注。PEP 3107已经提供了Type Hints所需要的语法,PEP 484提供了一个额外的模块typing,提供

了Callable、GenericSequence,TypeVar等GenericMeta和TypingMeta来构造一些更复杂的组合类型,

对于TypingMeta类型的构造器还提供了Covariance和Contravariance选项。typing同时

以库的形式发布,可以通过pip3 install typing来安装,

用于支持Python 3.5以前版本的Python。typing模块还提供了typing.TYPE_CHECKING这一常量来

对不会被解释执行的代码执行类型检查,在类型检查阶段或静态分析阶段,type.TYPE_CHECKING的

值为True。PEP 484还定义了Type Comments,由于在Python中并没有First-class syntax用来支持

Type Annotation,对于某些比较复杂的表达式,可以用来Type Comments来进行类型标注:

x = [] # type: List[float]

x, y, z = [], [], [] # type: List[int], List[int], List[str]

x, y, z = [], [], [] # type: (List[int], List[int], List[str])

x = [

1,

2,

] # type: List[int]

在可以预见的未来,CPython本身不会引入原生的类型推导和检查的支持,PEP 484中有

这样一段话:

Python will remain a dynamically typed language, and the authors have no desire

to ever make type hints mandatory, even by convention.

Type Hints的另一个可能的用途是用来辅助实现Function/Method Overloading,提供Multiple

Dispatch的能力,目前typing.overload仅能用于stub files。PEP 484中表示,Overloading

Syntax与Multiple Dispatch由于而这目的和用途不同,应该各自独立实现。overloading.py

以库的形式通过Decorator的形式实现了基本的Function/Method Overloading的支持,并且

支持使用PEP 484定义的类型标注协议以及typing里的构造器定义的复合类型。

想要真正做静态类型推导检查,仍然需要使用mypy

之类的工具。mypy已经支持PEP 484,mypy发现类型错误是的错误信息也非常友善,在实际项目

中使用mypy非常有利于提升项目质量。

Gradual Typing

类型决定了一个程序中一个符号的取值范围。Indiana大学的Jeremy Siek提出的Gradual Typing

可以作为一种弥补的方案。Gradual Typing也是Python的Type Hints以及mypy等类型检查工具的理论基础。

Gradual typing allows one to annotate only part of a program, thus leverage desirable

aspects of both dynamic and static typing.

具体来说,如果变量a_value的类型和标识符a_variable一致,那么就可以将a_value赋值给a_variable。

对于两个不同的类型,“一致(consistant)”包含三种含义:

如果类型t1是类型t2的子类型,则t1和t2一致。

Any类型与其他任何类型一致。

任何类型都可以视作Any类型的子类型,也就意味着任何类型都与Any类型一致。

具体举例,定义两个类型:

class A: ...

class B(A): ...

定义一个A类型的变量a,则a具有类型A,由于B类型是A类型的子类型,与A类型一致,因此

标识符a可以被赋一个B类型的值:

a = A() # type: A

a = B()

反过来,定义一个B类型的变量b,不能给标识符b赋一个A类型的值:

b = B() # type: B

b = A() # error.

Any类型可以视为类型继承图的根节点,因此,可以给Any类型的标识符赋任何类型的值:

c = ... # Any

c = A()

c = B()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值