Python 3.5中最受关注的特性之一是类型提示
本文和本篇文章都提到了类型提示的一个例子,同时也提到了负责任地使用类型提示。有人能解释更多关于它们的信息吗?它们应该在什么时候使用,什么时候不使用
我建议阅读PEP 483和PEP 484,并观看Guido关于类型暗示的演示
简言之:类型暗示就是这些词的字面意思。提示正在使用的对象的类型
由于Python的动态特性,推断或检查所使用对象的类型尤其困难。这一事实使得开发人员很难理解他们没有编写的代码中到底发生了什么,最重要的是,对于许多IDE(我想到的是PyCharm和PyDev)中的类型检查工具,它们受到限制,因为它们没有任何对象类型的指示。因此,他们试图推断出(如演示中所述)成功率约为50%的类型
从类型提示演示文稿中选取两张重要幻灯片:
为什么键入提示?
- 帮助类型检查器:通过提示您希望对象是什么类型,类型检查器可以轻松检测是否传递了一个类型不符合预期的对象
- 文档帮助:第三方查看您的代码时,会知道您希望在哪里使用它,并且不会让他们看到
类型错误 - 有助于IDE开发更准确、更健壮的工具:开发环境将更适合在知道对象类型时建议适当的方法。您可能在某些IDE中遇到过这种情况,点击
,并弹出未为对象定义的方法/属性
为什么使用静态类型检查器?
- 尽早发现bug:我相信这是不言而喻的
- 项目越大,您就越需要它:同样,这是有意义的。静态语言提供了健壮性和
缺乏动态语言。应用程序越大、越复杂,控制和可预测性就越强(从
行为方面)你需要的 - 大型团队已经在运行静态分析了:我猜这验证了前两点
作为这个小介绍的结束语:这是一个可选的功能,据我所知,它的引入是为了获得静态键入的一些好处
通常不需要担心它,而且肯定不需要使用它(特别是在使用Python作为辅助脚本语言的情况下)。当开发大型项目时,它应该很有帮助,因为它提供了急需的健壮性、控制和额外的调试功能
用mypy键入提示:
为了使这个答案更完整,我认为进行一点演示是合适的。我将使用mypy,该库激发了PEP中显示的类型提示。这本书主要是写给任何碰到这个问题并想知道从哪里开始的人的
在此之前,让我重申以下几点:PEP 484不强制执行任何内容;它只是为功能设定一个方向
注释和建议如何执行类型检查的指南。您可以注释您的函数和
你想暗示多少就暗示多少;无论是否存在注释,脚本仍将运行,因为Python本身不使用注释
无论如何,正如政治公众人物中所述,暗示类型通常应采取三种形式:
- 功能注释(PEP 3107)
- 内置/用户模块的存根文件
- 特殊的
#类型:输入补充前两种形式的注释。(请参阅:什么是变量注释?了解Python 3.6对#type:type注释的更新)
此外,您还需要将类型提示与Py3.5中引入的新的键入模块结合使用。在其中,许多(附加的)ABC(抽象基类)与辅助函数和装饰器一起定义,用于静态检查。集合中的大多数abc.abc都包括在内,但以通用的形式,以便允许订阅(通过定义\uuu getitem\uuuuuuuuuu()方法)
对于任何有兴趣更深入地解释这些内容的人来说,mypy文档写得非常好,并且有大量代码示例演示/描述其检查器的功能;这绝对值得一读
功能注释和特殊注释:
首先,观察我们在使用特殊注释时的一些行为是很有趣的。特殊#类型:类型注释
如果无法直接推断对象的类型,则可以在变量指定期间添加,以指示对象的类型。简单的作业是
通常很容易推断,但其他的,如列表(就其内容而言),则不能
注意:如果我们想使用容器的任何派生类型,并且需要指定该容器的内容,我们必须使用键入模块中的通用类型这些支持索引。
通用列表,支持索引。
从输入导入列表开始
#在本例中,该类型很容易推断为type:int。
i=0
#即使类型可以推断为类型列表的类型
#无法知道此列表的内容。
#通过使用type:List[str],我们表示希望使用字符串列表。
a=[]#类型:列表[str]
#将int添加到列表中
#静态上是不正确的。
a、 附加(i)
#附加字符串是可以的。
a、 附加(“i”)
打印(a)#[0,‘i’]
如果我们将这些命令添加到一个文件中,并使用解释器执行它们,那么一切都会正常工作,并且打印(a)只打印
列表a的内容。#type注释已被丢弃,被视为没有附加语义的普通注释
另一方面,通过使用mypy,我们得到以下响应:
(蟒蛇3)[email protected]:mypy typeHintsCode.py
typesInline.py:14:错误:参数1到;附加“;“的;列表“;“具有不兼容类型”;int";;“预期”;str";
表示str对象的列表不能包含int,静态地说,它是正确的。这可以通过遵循a的类型并仅添加str对象来解决,或者通过更改a的内容类型来表明任何值都是可接受的(在从键入导入任何后,直观地使用列表[any]执行)
函数注释以param_name:type的形式添加在函数签名中的每个参数之后,并使用->;在结束函数冒号前键入符号;所有注释都以方便的字典形式存储在该函数的\uuuuuu annotations\uuuu属性中。使用一个简单的示例(不需要键入模块中的额外类型):
def注释(x:int,y:str)->;布尔:
返回x<;Y
annotated.\uuuuu annotations\uuuu属性现在具有以下值:
{'y':<;class'str'>;,'return':<;class'bool'>;,'x':<;class'int'>;}
如果我们是一个完全的新手,或者我们熟悉Python 2.7的概念,因此不知道注释的比较中潜伏的类型错误,那么我们可以执行另一个静态检查,捕捉错误并为我们节省一些麻烦:
(蟒蛇3)[email protected]:mypy typeHintsCode.py
typeFunction.py:注:在函数中;加上“注释”:
typeFunction.py:2:错误:不支持>;的操作数类型;(“str”和“int”)
除此之外,使用无效参数调用函数也会被捕获:
注释(20,20)
#mypy抱怨说:
TypeHintCode.py:4:错误:参数2到";注「;“具有不兼容类型”;int";;“预期”;str";
这些可以扩展到基本上任何用例,捕获的错误可以扩展到基本调用和操作之外。你喜欢的类型
我可以检查一下它们是否真的很灵活,我只是给出了它的潜力的一个很小的潜在峰值。查看键入模块中的
PEP或mypy的文档将使您对所提供的功能有更全面的了解
存根文件:
存根文件可用于两种不同的非互斥情况:
- 您需要对不希望直接更改其函数签名的模块进行类型检查
- 您希望编写模块并进行类型检查,但还希望将注释与内容分开
存根文件(扩展名为.pyi)是您正在制作/想要使用的模块的带注释的接口。它们包含
要键入的函数的签名将在丢弃函数体的情况下进行检查。要了解这一点,请给出一组
名为randfunc.py的模块中的三个随机函数:
def消息:
印刷品
def内容(myIterable):
返回[i为myIterable中的i,如果i%2==0]
def联合收割机(messageFunc,itFunc):
messageFunc(“打印Iterable”)
a=可变内容(范围(1,20))
返回集(a)