在本指南中,您将了解Python类型检查。在传统上,Python解释器以灵活但隐性的方式处理。最新版本的Python允许您指定可以通过不同工具使用的公式提示,以帮助您开发代码,以帮助您开发代码。更有效。
通过本教程,您将学习以下内容:
这是一个综合指南,可以涵盖许多字段。类型和正面和负面的类型将使您了解类型检查的工作原理,并且在有用时会引入。
所有编程语言都包含某种类型的系统,该系统形成可以处理的对象以及如何处理这些类别。例如,类型系统可以定义数字类型,其中42是数字类型对象的示例。
Python是一种动态类型的语言。这意味着仅在代码期间检查Python解释器,并允许在其生命周期中更改变量的类型。以下示例演示了Python的动态类型:
在上面的示例中,如果从未运行,则尚未通过类型检查。一种错误。
查看下一个示例,如果更改变量值的类型
type()返回对象的类型。这些示例确认事物的类型可以更改事物,并且正确地推断出Python在更改过程中正确地推断出该类型。
与动态类型相反,是静态类型。实施静态类型检查无需运行程序。在大多数静态类型语言中,在程序期间完成了汇编。例如,C和Java,
对于静态类型,尽管可能存在将变量转换为不同类型的机制,但通常不允许变量更改类型。LET查看静态类型语言的快速示例。请考虑以下Java代码段:
第一行声明事物的类型是字符串,因此后续分配还必须指定字符串类型。如果您给出东西= 2,则会犯错,但是Python不会犯错。
虽然,Python始终是一种动态类型的语言。
与大多数其他静态类型语言工作方法不同,该类型提示本身不会导致Python强制执行该类型。顾名思义,提示只是推荐类型。
在谈论蟒蛇时经常使用的另一个术语是鸭子打字。该昵称来自“如果它像鸭子一样行走,就像鸭子一样,那就像鸭子,那一定是鸭子”(或任何零钱)。
Duck Type是与动态类型有关的概念,其中对象的类型或类别不像其定义方法那样重要。根本不需要检查Duck Type的类型,而是检查给定方法还是属性是存在。
在下面的示例中,您可以在Python的所有对象中使用Len()的魔术函数Len()方法:
实际的LAN()方法在下面实现:
发现对象还可以使用诸如str,list和dict的LEN方法,但是您需要重写Len Magic函数。
在本节中,您将看到如何将类型提示添加到函数。以下功能通过添加适当的大写字母和装饰线将文本字符串转换为标题:
默认情况下,该函数将对齐的左标题返回到下一行。通过将对齐徽标设置为false,您也可以选择使用o String:
是时候向我们的第一个类型添加提示了!要将有关类型的信息添加到该函数,只需对参数评论,然后返回值如下:
文本:str表示文本值类型为str,相似,可选参数对齐将其类型指定为bool,并给定默认值true。最后, - > str代表函数标题()返回值类型为str。
在代码样式方面,PEP 8建议如下::
但是,如果未指定参数类型的类型,则程序不会是错误。目前,您可以使用类型检查模块来通过提示内容(例如mypy.you可以通过pip安装)来确定类型输入是否正确:
将以下代码放在名为headlines.py的文件中:
然后通过mypy运行上面的文件:
根据类型提示,Mypy可以告诉我们我们在第10行中使用了错误的类型
这表明问题参数名称对齐不是很好。好的是,参数是布尔类型。我们将代码更改为以下内容,然后更改为高度可识别的参数名称中心。
再次运行文件,发现没有错误提示,好的。
然后你可以打印结果
第一个标题与左侧对齐,第二个标题在中间。
该类型提示的增加促进了IDE的代码提示功能。我们看到以下文本使用。您可以获得一些方法和熟悉str.type提示可以帮助您构建和维护更清晰的体系结构。写作类型的行为促使您迫使您考虑程序中的类型。尽管Python的动态特征是其重要资产之一,有意识地依靠鸭子类型是一件好事。对于重载方法或多个回报,这是一件好事。
应该注意的是,启动时类型提示将带来轻微的损失。如果您需要使用类型模块,则导入时间可能很长,尤其是在短脚本中。
因此,您是否应该在代码中使用静态类型检查?这不是全部或一无所有。提示将被静态类型检查器忽略。因此,只要它可以增加您的价值,就可以继续将类型添加到关键组件中,您就可以继续。
某些经验是否添加项目中的类型的经验规则:如果您只是开始学习Python,则可以安全地等待类型提示,直到有更多的经验。
类型提示说,短期投掷脚本中的值增加很小。在其他库中,尤其是在PYPI上发布的库中,该类型提示将增加很多价值。库的其他代码需要这些类型提示纠正类型的提示。
在较大的项目中,类型提示可以帮助您了解代码中的类型如何流动。强烈建议您这样做。这在与他人合作的项目中尤其如此。
Bernat Gabor在他的文章“ Python类型的状态”中建议,只要值得编写单元测试,就应使用类型提示。他们帮助开发人员编写更好的代码。
注释是在Python 3.0中引入的,一开始没有具体目的。它们只是与任何表达式和函数参数和返回值相关的方法。
多年后,PEP 484根据Jukka Lehtosalo博士的项目所做的工作来定义如何将类型提示添加到Python代码中。添加类型提示的主要方法是使用注释。更常见的是,这也意味着注释应主要保留类型提示。
以下各章将解释如何在类型提示的上下文中工作。
我们还提到该功能的注释以下是:
对于参数,语法是参数:注释和返回类型的用途 - >注释。请注意,注释必须是有效的python表达式。
以下简单示例添加到计算圆形长度的功能中:
圆周对象的注释魔法函数可以输出函数的注释信息。
有时您可能会对Mypy的解释如何解释您的类型提示感到困惑。对于这些情况,有一些特殊的mypy表达式:remote type()和揭示local()。键入它推断。例如,将以下代码保存为Replay.py。
然后通过mypy运行上述代码
即使没有任何注释,MyPy也正确地推断了数学中的构建类型。以及我们的局部变量半径和情况。
注意:上述代码需要通过mypy运行。如果您使用Python运行,将报告错误。此外
有时,类型检查器还需要帮助确定变量的类型。可变性注释在PEP 526中定义并在Python 3.6中引入。语法和函数参数相同:
PI被宣布为浮动类型。
注意:静态类型检查器可以很好地确定3.142是浮点数,因此在此示例中不需要PI注释。随着您对Python类型系统的了解越来越多,您将看到有关可变注释的更多示例。。可变注释存储在模块级注释词典中::
即使未分配变量,也可以通过注释获得类型。尽管未在python中分配值的变量是错误的。
如上所述,注释是在Python 3中引入的,它们没有将其移植到Python2。这意味着,如果您编写了需要支持旧版本Python的代码,则无法使用注释。
要向函数添加类型注释,您可以执行以下操作:
类型注释只是注释,因此可以在任何版本的Python中使用。
类型注释是由类型检查器直接处理的,因此没有注释字典对象:
类型注释必须以类型开头:字面意思,并定义相同的行或下一行与函数定义。如果要使用一些参数来对函数进行评论,则可以使用逗号将每个类型分开:
您也可以在自己的行上编写每个参数:
通过Python和Mypy的示例:
如果您传递字符串宽度=“ full”,则再次运行mypy会出现错误。
您还可以将类型注释添加到变量中。这与您将类型注释添加到参数的方式相似:
上面的示例可以检测到PI是浮动类型。
因此,当将类型提示添加到您自己的代码中时,您是否应该使用笔记或类型说明?简而言之:尽可能多地使用注释,并在必要时使用类型注释。注意提供更清晰的语法以使类型信息更接近您的代码。还可以正式推荐编写类型提示的方法,并将在将来进一步开发和正确维护。
类型注释可能更详细,这可能与代码中的其他类型的注释相冲突,例如Linter指令。但是,它们可以在不支持注释的代码库中使用。
还有一个隐藏的选项3:启动文件。下,当我们讨论将类型添加到第三方库时,您将了解这些。
启动根文件可以在任何版本的Python中使用,而成本是维护第二组文件。从基础上,如果无法更改原始源代码,则只需要使用存款文件即可。
到目前为止,您仅在类型提示中使用基本类型,例如str,float和bool。这种类型的系统并获得简单的纸牌游戏。您将看到如何指定:
序列和映射的类型,例如元组,列表和关键名称的字典,使代码更易于读取功能和方法,而无需返回任何类型的对象。在简要介绍了某些类型的理论之后,您将看到使用Python的类型进行Morespection。您可以在此处找到代码示例:
以下示例显示了常规卡的实现:
每张卡都表示为西装和等级。小组到四个球员。
最后,play()玩游戏。现在,它只会通过建立洗牌并向每个玩家发送卡片来准备一张纸牌游戏。以下是典型的输出:
让我逐步扩展上述代码。
让我们在卡游戏中添加类型提示。用来表示卡本身的元组。
对于STR,Float和Bool等简单类型,添加类型提示与使用类型本身一样简单:
对于复合类型,可以执行相同的操作:
上述注释仍然不完美。例如,我们只知道这是列表类型,但我们不知道
打字模块为我们提供了更准确的定义:
应该注意的是,这些类型中的每一种都以大写字母开头,它们都使用方括号来定义类型:
键入还包括许多其他类型,例如Count,Deque,Frozense,Nequtuple和Set。此外,该模块还包括其他类型。您将在后续部分中看到。
让我们回到扑克游戏。因为该卡由由2个str组成的元素定义。因此,您可以编写元组[str,str],因此函数create_deck()返回值的类型是列表[tuple [str,str]。] ..
除返回值外,您还将Bool类型添加到可选的Shuffle参数中。
注意:元组和列表的语句是差异无法掩饰,通常由固定数量的不同类型的元素组成。例如,我们将卡表示为一组集合和级别。您为N Yuan组编写元组[T_1,T_2,...,T_N]。
该列表是一个可变序列,通常由相同类型的元素(例如卡列表)组成。列表中有多少个元素的记录,注释中只有一种类型:列表[t]。
在许多情况下,您的函数会期望一定的顺序,并且不在乎它是列表还是组。在这些情况下,您应该使用键入。Sequesence当注释函数参数时:
使用序列是鸭型的典型示例。这也意味着您可以使用len()和。getItitem()和其他方法。
当使用嵌套类型(例如卡集)时,类型提示可能会变得非常麻烦。您可能需要仔细观察列表[tuple [str,str]],以确定它是否与我们的卡一致。
现在考虑如何对Deal_hands()函数发表评论:
这太麻烦了!
不害怕,我们还可以使用别名将注释类型分配给新变量,该变量很方便以后使用,就像以下内容一样:
现在,我们可以使用别名对先前的代码发表评论:
类型的别名使我们的代码变得更加简洁。我们可以打印变量以查看内部的特定值:
当输出甲板时,您可以看到其最终类型。
对于没有返回值的函数,我们可以指定无:
通过mypy测试上述代码
作为一个更具特殊情况,请注意,您还可以评论您从未期望正常返回功能。这是使用Noreturn完成的:
因为black_hole()总是会导致异常,所以它永远不会正确返回。
让我们回到我们的纸牌游戏示例。在游戏的第二版中,我们像以前一样向每个玩家分发一张卡片。只会播放随机通行证:
请注意,除了更改play()之外,我们还添加了两个需要类型提示的新功能:select()和player_order()。在讨论我们如何向其添加类型提示之前,以下是运行游戏输出的示例:
在此示例中,播放器P3被随机选择为起始播放器。相反,每个播放器都会播放一张卡:第一个P3,然后是P4,然后是P1,最后是P2。将继续播放卡。
选择()适用于名称列表和卡列表(以及任何其他序列)。添加类型提示的一种方法是:
这意味着或多或少:项目是一个可以包含任何类型项目的序列,并且选择()将返回任何类型的项目的任何类型的项目。不太严格,请考虑以下示例:
尽管MyPy会正确地推断字符串的名称,但由于使用任何类型,在调用select()之后,信息将丢失:
众所周知,是否使用任何使用mypy并不容易检测。
任何问题都在于您不必要丢失类型信息。您知道,如果将字符串列表传递给选择(),它将返回字符串。
类型声明是一个特殊的变量语句,可以根据特定情况采用任何类型。LET我们创建一个类型变量,该变量有效地封装了选择()行为:
类型声明必须使用类型模块中的TypeVar定义
考虑其他一些例子:
前两个示例应该具有类型的str和int,但是后两个示例呢?单个列表项目的类型不同。在这种情况下,所选类型变量可用于适应最大努力:
如您已经看到的那样,Bool是int sub -type,也是float的子型。因此,在第三个示例中,可以将select()的返回值视为floating -point number.例如,str和int之间没有子型关系,因此返回值的最好之处在于它是一个对象。
请注意,这些示例都不会导致类型错误。
您可以通过列出可接受类型来限制类型变量:
现在,Chosable只能是str或float,Mypy会注意到最后一个示例是一个错误:
还应注意的是,在第二个示例中,即使输入列表仅包含int对象,此类型也被认为是浮点类型。这是因为可选的限于str和float,而int是sub -type浮子。
在我们的纸牌游戏中,我们要限制选择()仅使用str和卡类型:
我们简要提及序列和群集列表。正如我们指出的那样,可以将序列视为鸭型,因为它可以实现任何对象。len()和getItem()。
回顾引言中的以下示例:
Len()方法可以返回实现Len Magic函数的对象的任何长度。那么,如何在len()中添加类型提示,尤其是类型OBJ类型表示形式?
答案隐藏在学术术语结构子类型中[https://en.wikipedia.org/wiki/wiki/structural_type_system]结构亚型的方法是基于它们是正常还是结构性:在正常系统中,比较类型基于名称和声明。大多数Python类型系统都是名义上的,因为它们的子型关系可以使用而不是float。
在结构系统中,类型之间的比较基于结构。您可以定义结构类型“ size”,其中包括所有定义的实例。len(),无论其名义类型如何。
目前,它正在通过PEP 544将成熟的结构类型系统带到Python,该系统旨在添加一个称为协议的概念。尽管大多数PEP 544已在Mypy中实现。
该协议指定了一种或多种实施方法。
此外,以下模块还包括以下模块容器,具有疑虑,已久有的和上下文操者。
您还可以通过在typing_extensions模块中导入协议协议对象,然后编写继承该方法的子类,如下:如下:
您需要安装通过PIP上面使用的第三方模块
Python中有一个公共模式,该模式是设置参数无的默认值。这通常是为了避免可变的轻度识别问题,或者允许明显的特殊行为。
在上面的卡片示例中,函数player_order()使用无作为参数启动的默认值,表明尚无指定的播放器:
类型提示提出的挑战是开始是字符串。但是,它还可以使用特殊的非弦值“无”。
要解决上述问题,您可以使用可选类型:
联合[无,str]等效于联合类型,表示该参数的值类型为str。
请注意,使用可选或联合时,您必须注意是否在背面操作该变量。进行静态检查:
Mypy告诉您,您尚未处理任何开始。
您还可以使用以下操作来声明参数启动的类型。
如果您不希望Mypy报告错误,则可以使用该命令
接下来,我们将重写上述扑克游戏,以使其看起来更面向对象和适当使用的注释。
将我们的纸牌游戏转换为以下类,卡,甲板,玩家,游戏,以下是代码实现。
好吧,让我们添加下面的注释
方法类型的类型与函数类型非常相似。唯一的区别是,由于它是类的实例,因此不需要注释自我参数。卡类的类型易于添加:
注意:init()的返回值始终不
类别和类型之间存在相应的关系。例如,所有卡的所有实例形式形式card类型。要使用类作为类型,只需使用类的名称。例如:甲板(卡组)由集合组成卡对象。
但是,当您需要引用当前定义的类时,此方法不太有效。例如,deb.create()类方法返回具有甲板类型的对象。甲板类尚未完全定义。
在这种情况下,您可以在注释中使用字符串文本。就像下面的“甲板”一样,返回类型被声明,然后添加DOCSTRING注释以进一步解释该方法。
玩家类还可以将DEB用作类型语句。因为我们以前已经定义了它,所以我们已经定义了
通常,在运行时不使用注释。这提供了推迟注释的动机。该建议不是评估对Python表达式的注释并存储其值,而是存储字符串字符串表示表单,仅在需要时对其进行评估。
该功能计划在Python 4.0中成为标准。
使用将来后,您可以使用甲板对象替换字符串“甲板”。
如前所述,不应注释self或cls参数。在一定程度上,这是不必要的,因为自我指向类别类别,因此它将具有类型。在卡片示例中,self具有隐藏的类型卡另外,将这种类型添加到它非常麻烦,因为它尚未定义此类。因此,您需要使用字符串“卡”来声明返回类型。但是,有一种情况可能需要评论自我或cls.考虑如果您拥有继承继承的超级阶级,并且有一种方法可以返回自我或CLS:
运行上述代码,Mypy会丢下以下错误:
问题在于,甚至继承了遗传的dog.newborn()和dog.twin()方法将返回狗,评论表明它们返回动物。
在这种情况下,您需要更加谨慎以确保正确的注释。返回类型应与类型类型的self或CLS匹配。可以使用TypeVar进行此操作。这些变量将跟踪实际传递给自我和CLS的内容:
在此示例中,需要注意以下几点:
类型可变的塔尼符号用于指示动物子类的实例。然后,然后
我们指定动物是塔尼姆的上限。指定结合意味着塔尼姆将是动物子类之一。这可以正确限制允许的类型。
typing.type []是类型()的类型。应该注意的是,CLS的类方法需要以此形式使用,并且不需要使用自我。
在面向对象的游戏版本中,我们在命令行上添加了播放器的选项。这是通过在程序名称之后列出播放器名称来完成的:
关于类型注释:即使名称是字符串的字符串,它也只能对每个名称的类型发表评论。
同样,如果有一种函数或方法接受** kwargs,则您只应对每个可能的关键字参数的类型发表评论。
函数是python中的一种对象。按类型的callace对象。通常表示参数的类型和返回值。例如,可callable [[A1,A2,A3],RT]代表一个函数,该函数具有三个具有A1,A2和A3类型的参数该函数的返回类型为RT。
在下面的示例中,函数do_twice()传递到可呼叫类型的func参数中,并且传输函数的参数类型为str,返回值类型为str.例如,参数create_greeting。
让我们结束在红色疗法游戏的完整示例中。如果有可能,球员轮流打牌并跟随领导者。在第一张甲板上打出最高牌的球员赢得了比赛,并成为下一轮的首发球员。玩家不能使用非,除非?已经在以前的技能上发挥了作用。在玩所有卡后,如果您获得一些卡片,玩家将获得积分:?Q是比赛的几轮13分,直到获得超过100分。得分最少的球员获胜
可以在线搜索特定的游戏规则。
在此示例中,没有看到很多新类型的概念。因此,我们不会详细讨论此代码,而是将其用作注释代码的示例。
对上述代码有一些关注:
对于难以使用或键入变量的类型类型,例如魔术功能,您可以使用@Overload装饰。
子类对应于子类型,因此您可以在任何玩家需要的地方使用人游戏。
当子类从超级类重新完成时,必须匹配类型的注释。示例,请参见humanplayer.play_card()。启动游戏时,您可以控制第一个玩家。输入您要选择您想要的卡的编号玩。以下是游戏的示例。突出显示显示的行显示了玩家的选择:
所有键入方法的当前使用方案已经结束。
Zhihu列:https://zhuanlan.zhihu.com/p/110176242
