Python 3.8中的类型注记

2020-09-18 16:12:45

Python如此容易入门的原因之一是它具有动态类型。您不必指定变量的类型,只需将变量用作数据容器的标签。但在较大的项目中,拥有类型是有帮助的。如果您有一个没有记录的没有类型的函数,可能还有糟糕的变量命名,新的开发人员将会遇到困难。幸运的是,在带有PEP526🎉的Python3.6中添加了变量注释。

这篇文章的写作方式是,您可以很容易地在“mypy”部分之后停下来,然后只看一下各个部分。

有类型注释很好,但是您需要检查它们!不管您是否使用CPython、PyPy或其他更奇特的工具,Python运行时都不会这样做。

必须使用--IGNORE-MISSING-IMPORTS标志,否则您将收到许多这样的消息:

错误:跳过分析“setuptools”:找到模块,但没有类型提示或库存根。

为方便起见,我通常添加一个setup.cfg文件,在该文件中指定我始终希望应用此标志:

然后,您可以通过将以下部分添加到setup.cfg来pip install pytest-mypy,并确保在运行pytest时始终执行mypy:

需要注意的是,Python社区和mypy都假设您来自非类型注释代码库。他们想让您轻松切换到带注释的代码,从而支持渐进式键入。然而,这意味着如果您不注释代码,您可能会错过错误!Mypy有很多旗帜可以帮助你行动。您不需要注释所有内容。

键入模块添加了对类型提示的支持。它包含一些最常用的类型:List、Dict和Tuple。

类似地,您可以通过dict[str,int]注释字典将字符串映射到整数。所以list、dict和tuple都是泛型。Any只是指定可以在这些容器中包含任意数据的一种方式。当您开始向更大的代码库添加类型批注时,在开始时使用Any是合理的。

如前所述,mypy和Python支持渐进式输入。有时,您需要让类型检查器静音才能继续(希望稍后能修复它,🤞)。有几种方法可以通过键入来完成此操作:

Cast(SomeClass,变量):有时mypy不够智能,所以您可以告诉它您使用的是哪种类型。在我知道打字之前我做过几次。超载。或者,您也可以添加assert isinstance(Variable,Someclass)。

因为你经常需要接受一些类型,而不接受任何类型,所以也有打字的问题,这是可选的。可选的[SomeType]与UNION[SomeType,None]相同。

键入.List类型表示列表。正如Jochen Ritzel所说的那样,Sequence是“一个随机访问的可迭代的”。例如,字符串是序列[any],而不是列表[any]。

与示例LIST和SEQUENCE类似,tying.Dict主要用于表示字典,而typeing.Mapping更为通用。StacksonStacks给出了一个很好的答案。

TypedDict是在PEP-589中引入的,它提供了指示字典应该具有哪些键以及这些键的值具有哪些类型的可能性。PEP中的示例很好地说明了这一点:

通过键入import TypedDict class Movie(TypedDict):Name:Str Year:INT Movie:Movie={';Name';:';Blade Runner';,';Year';:1982}。

默认情况下,它必须拥有所有密钥。您可以通过设置TOTALITY:Class Movie(TypedDict,Total=false)使关键点成为可选的。

键入模块知道更多类型,它们有时难以区分。例如,List、Sequence和Iterable之间有什么不同?请看一下收藏文档。

并非所有字符串都包含相同类型的内容。它们可以表示USER_ID、USER_NAME、PASSWORD_HASH、…。

特别是对于身份证,我已经看到这变得一团糟。我认为为那些不同的字符串类型创建自己的类是非常荒谬的,因为创建类通常是开发和维护开销。那么,你是做什么的?

T=TypeVar(';T';)#可以是任何A=TypeVar(';A';,字符串,字节)#必须是字符串或字节。

它看起来和新型的很相似,但是很不一样。NewType用于为给定类型创建有意义的别名。TypeVar用于指定泛型,例如,在下面的示例中,保证两个变量x和y属于同一类型,但它可以是任何类型:

Tying.Union有时是一种反模式,因为您还可以重载函数,如Josh Reed所示:

最近,我发现自己在模块级上进行了相当大的导入,这仅仅是因为类型检查。这感觉不对劲,所以我请求帮助。解决方案很简单:键入.TYPE_CHECKING。这在运行类型检查器时为真,但在正常运行❤️期间为假。

PEP544引入了结构子类型,并在Python3.8中引入。它给人的感觉就像Java中的Interfaces,其工作方式如下所示:

请注意,没有函数体。在该定义之后,您就可以像使用任何类型一样使用SupportsClose。

最酷的是,类foo与SupportsClose没有显式关系!它只是通过它的结构联系在一起的!

存根文件以.pyi结尾。如果mypy找到一个.py文件和一个.pyi文件,它只加载.pyi文件。它们类似于C++中的头文件,但对于Python而言。不使用函数体,而使用省略号...:

Pyright是微软编写的Python静态类型检查器,pyre是Facebook编写的,pytype是Google编写的。他们都自称比Mypy快,被采用率都比Mypy低。到目前为止我还没有用过它们。

$pip install pyre-check pytype#是,pyright是用打字稿写的...。$npm安装-g pyright。

变量注释还可以用来删除大量样板代码。例如,pydtic可以帮助您进行序列化/反序列化:

Andreas Dewes:在Python3中输入注释:Whats,Whys&;Wows!在2017年的EuroPython大会上。在YouTube上。