Python 3.5 中的类型提示是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32557920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are type hints in Python 3.5?
提问by Vaulstein
One of the most talked about features in Python 3.5 is type hints.
Python 3.5 中最受关注的特性之一是类型提示。
An example of type hintsis mentioned in this articleand this onewhile also mentioning to use type hints responsibly. Can someone explain more about them and when they should be used and when not?
的一个例子类型提示中提到的这篇文章和这一个,同时还提负责任地使用类型提示。有人可以解释更多关于它们的信息,何时应该使用,何时不使用?
采纳答案by Dimitris Fasarakis Hilliard
I would suggest reading PEP 483and PEP 484and watching thispresentation by Guido on Type Hinting.
我建议阅读PEP 483和PEP 484和观看该演示由Guido的类型提示。
In a nutshell: Type hinting is literally what the words mean, you hint the type of the object(s) you're using.
简而言之:类型提示是字面上的意思,您提示您正在使用的对象的类型。
Due to the dynamicnature of Python, inferring or checking the typeof an object being used is especially hard. This fact makes it hard for developers to understand what exactly is going on in code they haven't written and, most importantly, for type checking tools found in many IDEs [PyCharm, PyDev come to mind] that are limited due to the fact that they don't have any indicator of what type the objects are. As a result they resort to trying to infer the type with (as mentioned in the presentation) around 50% success rate.
由于Python的动态特性,推断或检查正在使用的对象的类型特别困难。这一事实使开发人员难以理解他们尚未编写的代码中究竟发生了什么,最重要的是,对于许多 IDE [PyCharm、PyDev] 中发现的类型检查工具而言,这些工具由于以下事实而受到限制他们没有任何关于对象类型的指示。因此,他们试图以大约 50% 的成功率(如演示中提到的)推断类型。
To take two important slides from the Type Hinting presentation:
从 Type Hinting 演示中获取两张重要的幻灯片:
Why Type Hints?
为什么输入提示?
- Helps Type Checkers:By hinting at what type you want the object to be the type checker can easily detect if, for instance, you're passing an object with a type that isn't expected.
- Helps with documentation:A third person viewing your code will know what is expected where, ergo, how to use it without getting them
TypeErrors
. - Helps IDEs develop more accurate and robust tools:Development Environments will be better suited at suggesting appropriate methods when know what type your object is. You have probably experienced this with some IDE at some point, hitting the
.
and having methods/attributes pop up which aren't defined for an object.
- 帮助类型检查器:通过暗示您希望对象是什么类型,类型检查器可以轻松检测,例如,您传递的对象是否具有非预期的类型。
- 帮助文档:查看您的代码的第三方将知道预期的内容,因此,如何在不获取它们的情况下使用它
TypeErrors
。 - 帮助 IDE 开发更准确和健壮的工具:当知道您的对象是什么类型时,开发环境将更适合建议适当的方法。您可能在某些时候在某些 IDE 中遇到过这种情况,点击
.
并弹出未为对象定义的方法/属性。
Why use Static Type Checkers?
为什么要使用静态类型检查器?
- Find bugs sooner: This is self evident, I believe.
- The larger your project the more you need it: Again, makes sense. Static languages offer a robustness and control that dynamic languages lack. The bigger and more complex your application becomes the more control and predictability (from a behavioral aspect) you require.
- Large teams are already running static analysis: I'm guessing this verifies the first two points.
- 尽早发现错误:我相信这是不言而喻的。
- 您的项目越大,您就越需要它:同样,这是有道理的。静态语言提供了动态语言所缺乏的健壮性和控制力。您的应用程序越大越复杂,您就越需要控制和可预测性(从行为方面)。
- 大型团队已经在运行静态分析:我猜这验证了前两点。
As a closing note for this small introduction: This is an optionalfeature and, from what I understand, it has been introduced in order to reap some of the benefits of static typing.
作为这个简短介绍的结束语:这是一个可选功能,据我所知,引入它是为了获得静态类型的一些好处。
You generally do notneed to worry about it and definitelydon't need to use it (especially in cases where you use Python as an auxiliary scripting language). It should be helpful when developing large projects as it offers much needed robustness, control and additional debugging capabilities.
你一般不会需要它的担忧和绝对不需要使用它(尤其是在你使用Python作为辅助脚本语言的情况下)。它在开发大型项目时应该会有所帮助,因为它提供了急需的稳健性、控制和额外的调试功能。
Type Hinting with mypy:
用 mypy 类型提示:
In order to make this answer more complete, I think a little demonstration would be suitable. I'll be using mypy
, the library which inspired Type Hints as they are presented in the PEP. This is mainly written for anybody bumping into this question and wondering where to begin.
为了让这个回答更完整,我觉得稍微演示一下比较合适。我将使用mypy
,该库激发了类型提示,因为它们在 PEP 中呈现。这主要是为遇到这个问题并想知道从哪里开始的任何人而写的。
Before I do that let me reiterate the following: PEP 484doesn't enforce anything; it is simply setting a direction for function annotations and proposing guidelines for howtype checking can/should be performed. You can annotate your functions and hint as many things as you want; your scripts will still run regardless of the presence of annotations because Python itself doesn't use them.
在我这样做之前,让我重申以下内容:PEP 484不强制执行任何内容;它只是为函数注释设置一个方向,并就如何/应该执行类型检查提出指导方针。你可以注释你的函数并提示尽可能多的东西;无论是否存在注释,您的脚本仍将运行,因为 Python 本身不使用它们。
Anyways, as noted in the PEP, hinting types should generally take three forms:
无论如何,如 PEP 中所述,提示类型通常应采用三种形式:
- Function annotations. (PEP 3107)
- Stub files for built-in/user modules.
- Special
# type: type
comments that complement the first two forms. (See: What are variable annotations in Python 3.6?for a Python 3.6 update for# type: type
comments)
- 函数注释。( PEP 3107)
- 内置/用户模块的存根文件。
# type: type
补充前两种形式的特殊注释。(请参阅:Python 3.6 中的变量注释是什么?有关注释的 Python 3.6 更新# type: type
)
Additionally, you'll want to use type hints in conjunction with the new typing
module introduced in Py3.5
. In it, many (additional) ABCs (Abstract Base Classes) are defined along with helper functions and decorators for use in static checking. Most ABCs
in collections.abc
are included but in a Generic
form in order to allow subscription (by defining a __getitem__()
method).
此外,你要结合使用类型提示与新typing
中介绍模块Py3.5
。在其中,定义了许多(附加的)ABC(抽象基类)以及用于静态检查的辅助函数和装饰器。大多数ABCs
在collections.abc
被包括在内,但在一个Generic
形式,以允许订阅(通过定义一个__getitem__()
方法)。
For anyone interested in a more in-depth explanation of these, the mypy documentation
is written very nicely and has a lot of code samples demonstrating/describing the functionality of their checker; it is definitely worth a read.
对于任何对这些更深入的解释感兴趣的人,mypy documentation
它写得非常好,并且有很多代码示例演示/描述了他们的检查器的功能;绝对值得一读。
Function annotations and special comments:
函数注解和特殊注释:
First, it's interesting to observe some of the behavior we can get when using special comments. Special # type: type
comments
can be added during variable assignments to indicate the type of an object if one cannot be directly inferred. Simple assignments are
generally easily inferred but others, like lists (with regard to their contents), cannot.
首先,观察我们在使用特殊注释时可以获得的一些行为是很有趣的。# type: type
如果不能直接推断对象的类型,可以在变量赋值期间添加特殊注释以指示对象的类型。简单的赋值通常很容易推断,但其他的,比如列表(关于它们的内容),则不能。
Note:If we want to use any derivative of Containers
and need to specify the contents for that container we mustuse the generictypes from the typing
module. These support indexing.
注意:如果我们想使用任何派生类Containers
并且需要为该容器指定内容,我们必须使用模块中的泛型类型typing
。这些支持索引。
# generic List, supports indexing.
from typing import List
# In this case, the type is easily inferred as type: int.
i = 0
# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = [] # type: List[str]
# Appending an int to our list
# is statically not correct.
a.append(i)
# Appending a string is fine.
a.append("i")
print(a) # [0, 'i']
If we add these commands to a file and execute them with our interpreter, everything works just fine and print(a)
just prints
the contents of list a
. The # type
comments have been discarded, treated as plain comments which have no additional semantic meaning.
如果我们将这些命令添加到一个文件中并使用我们的解释器执行它们,一切都会正常运行并且print(a)
只打印 list 的内容a
。的# type
意见已丢弃,因为它们没有额外的语义含义普通的注释处理。
By running this with mypy
, on the other hand, we get the following responce:
mypy
另一方面,通过使用 运行它,我们得到以下响应:
(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
Indicating that a list of str
objects cannot contain an int
, which, statically speaking, is sound. This can be fixed by either abiding to the type of a
and only appending str
objects or by changing the type of the contents of a
to indicate that any value is acceptable (Intuitively performed with List[Any]
after Any
has been imported from typing
).
表示str
对象列表不能包含int
,从静态上讲,它是合理的。这可以通过遵守 的类型a
并且仅附加str
对象或通过更改内容的类型a
以指示任何值都是可接受的(直观地执行 with List[Any]
after Any
has been imported from typing
)来解决。
Function annotations are added in the form param_name : type
after each parameter in your function signature and a return type is specified using the -> type
notation before the ending function colon; all annotations are stored in the __annotations__
attribute for that function in a handy dictionary form. Using a trivial example (which doesn't require extra types from the typing
module):
param_name : type
在函数签名中的每个参数之后的表单中添加函数注释,并使用-> type
结束函数冒号之前的符号指定返回类型;所有注释都__annotations__
以方便的字典形式存储在该函数的属性中。使用一个简单的例子(不需要typing
模块中的额外类型):
def annotated(x: int, y: str) -> bool:
return x < y
The annotated.__annotations__
attribute now has the following values:
该annotated.__annotations__
属性现在具有以下值:
{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
If we're a complete noobie, or we are familiar with Py2.7
concepts and are consequently unaware of the TypeError
lurking in the comparison of annotated
, we can perform another static check, catch the error and save us some trouble:
如果我们是一个完全的菜鸟,或者我们熟悉Py2.7
概念,因此不知道TypeError
比较中的潜伏annotated
,我们可以执行另一个静态检查,捕获错误并为我们省去一些麻烦:
(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")
Among other things, calling the function with invalid arguments will also get caught:
除其他外,使用无效参数调用函数也会被捕获:
annotated(20, 20)
# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"
These can be extended to basically any use-case and the errors caught extend further than basic calls and operations. The types you
can check for are really flexible and I have merely given a small sneak peak of its potential. A look in the typing
module, the
PEPs or the mypy
docs will give you a more comprehensive idea of the capabilities offered.
这些基本上可以扩展到任何用例,并且捕获的错误比基本调用和操作扩展得更远。您可以检查的类型非常灵活,我只是对其潜力进行了一个小小的初步了解。查看typing
模块、PEP 或mypy
文档将使您对所提供的功能有更全面的了解。
Stub Files:
存根文件:
Stub files can be used in two different non mutually exclusive cases:
存根文件可用于两种不同的非互斥情况:
- You need to type check a module for which you do not want to directly alter the function signatures
- You want to write modules and have type-checking but additionally want to separate annotations from content.
- 您需要键入检查不想直接更改函数签名的模块
- 您想编写模块并进行类型检查,但还想将注释与内容分开。
What stub files (with an extension of .pyi
) are is an annotated interface of the module you are making/want to use. They contain
the signatures of the functions you want to type-check with the body of the functions discarded. To get a feel of this, given a set
of three random functions in a module named randfunc.py
:
存根文件(扩展名为.pyi
)是您正在制作/想要使用的模块的带注释的接口。它们包含您要使用丢弃的函数体进行类型检查的函数的签名。为了感受一下,在名为 的模块中给出一组三个随机函数randfunc.py
:
def message(s):
print(s)
def alterContents(myIterable):
return [i for i in myIterable if i % 2 == 0]
def combine(messageFunc, itFunc):
messageFunc("Printing the Iterable")
a = alterContents(range(1, 20))
return set(a)
We can create a stub file randfunc.pyi
, in which we can place some restrictions if we wish to do so. The downside is that
somebody viewing the source without the stub won't really get that annotation assistance when trying to understand what is supposed
to be passed where.
我们可以创建一个存根文件randfunc.pyi
,如果我们愿意,我们可以在其中设置一些限制。不利的一面是,在试图了解应该在何处传递的内容时,没有存根查看源代码的人将无法真正获得注释帮助。
Anyway, the structure of a stub file is pretty simplistic: Add all function definitions with empty bodies (pass
filled) and
supply the annotations based on your requirements. Here, let's assume we only want to work with int
types for our Containers.
无论如何,存根文件的结构非常简单:添加带有空体(pass
填充)的所有函数定义,并根据您的要求提供注释。在这里,假设我们只想使用int
容器的类型。
# Stub for randfucn.py
from typing import Iterable, List, Set, Callable
def message(s: str) -> None: pass
def alterContents(myIterable: Iterable[int])-> List[int]: pass
def combine(
messageFunc: Callable[[str], Any],
itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass
The combine
function gives an indication of why you might want to use annotations in a different file, they some times clutter up
the code and reduce readability (big no-no for Python). You could of course use type aliases but that sometime confuses more than it
helps (so use them wisely).
该combine
函数给出了您可能想要在不同文件中使用注释的原因,它们有时会使代码混乱并降低可读性(Python 的大禁忌)。您当然可以使用类型别名,但有时会造成混淆而不是帮助(因此请明智地使用它们)。
This should get you familiarized with the basic concepts of Type Hints in Python. Even though the type checker used has been
mypy
you should gradually start to see more of them pop-up, some internally in IDEs (PyCharm,) and others as standard python modules.
I'll try and add additional checkers/related packages in the following list when and if I find them (or if suggested).
这应该会让您熟悉 Python 中类型提示的基本概念。尽管使用了类型检查器,
mypy
您应该逐渐开始看到更多的弹出窗口,一些在 IDE 内部(PyCharm)和其他作为标准 python 模块。当我找到它们(或如果建议)时,我将尝试在以下列表中添加其他检查器/相关包。
Checkers I know of:
我知道的跳棋:
- Mypy: as described here.
- PyType: By Google, uses different notation from what I gather, probably worth a look.
Related Packages/Projects:
相关包/项目:
- typeshed:Official Python repo housing an assortment of stub files for the standard library.
- typeshed:官方 Python 存储库,包含标准库的各种存根文件。
The typeshed
project is actually one of the best places you can look to see how type hinting might be used in a project of your own. Let's take as an example the __init__
dunders of the Counter
classin the corresponding .pyi
file:
该typeshed
项目实际上是您可以查看如何在您自己的项目中使用类型提示的最佳场所之一。我们以对应文件中类的__init__
dundersCounter
为例.pyi
:
class Counter(Dict[_T, int], Generic[_T]):
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
@overload
def __init__(self, iterable: Iterable[_T]) -> None: ...
Where _T = TypeVar('_T')
is used to define generic classes. For the Counter
class we can see that it can either take no arguments in its initializer, get a single Mapping
from any type to an int
ortake an Iterable
of any type.
where_T = TypeVar('_T')
用于定义泛型类。对于Counter
该类,我们可以看到它可以在其初始值设定项中不带任何参数,Mapping
从任何类型获取单个到 anint
或获取Iterable
任何类型的an 。
Notice: One thing I forgot to mention was that the typing
module has been introduced on a provisional basis. From PEP 411:
注意:我忘记提及的一件事是该typing
模块是临时引入的。来自PEP 411:
A provisional package may have its API modified prior to "graduating" into a "stable" state. On one hand, this state provides the package with the benefits of being formally part of the Python distribution. On the other hand, the core development team explicitly states that no promises are made with regards to the the stability of the package's API, which may change for the next release. While it is considered an unlikely outcome, such packages may even be removed from the standard library without a deprecation period if the concerns regarding their API or maintenance prove well-founded.
临时包可能会在“升级”到“稳定”状态之前修改其 API。一方面,这种状态为包提供了正式成为 Python 发行版一部分的好处。另一方面,核心开发团队明确表示不承诺包的 API 的稳定性,这可能会在下一个版本中发生变化。虽然这被认为是不太可能的结果,但如果对其 API 或维护的担忧被证明是有根据的,这些包甚至可以在没有弃用期的情况下从标准库中删除。
So take things here with a pinch of salt; I'm doubtfull it will be removed or altered in significant ways but one can never know.
所以拿一撮盐来这里;我很怀疑它会以重要的方式被删除或改变,但人们永远不会知道。
**Another topic altogether but valid in the scope of type-hints: PEP 526
: Syntax for Variable Annotationsis an effort to replace # type
comments by introducing new syntax which allows users to annotate the type of variables in simple varname: type
statements.
**另一个主题完全但在类型提示范围内有效PEP 526
::变量注释的语法是# type
通过引入允许用户在简单varname: type
语句中注释变量类型的新语法来替换注释的努力。
See What are variable annotations in Python 3.6?, as previously mentioned, for a small intro on these.
请参阅Python 3.6 中的变量注释是什么?,如前所述,关于这些的小介绍。
回答by tsvenson
The newly released PyCharm 5 supports type hinting. In their blog post about it (see Python 3.5 type hinting in PyCharm 5) they offer a great explanation of what type hints are and aren'talong with several examples and illustrations for how to use them in your code.
新发布的 PyCharm 5 支持类型提示。在他们关于它的博客文章中(请参阅PyCharm 5 中的 Python 3.5 类型提示),他们很好地解释了类型提示是什么,以及如何在代码中使用它们的几个示例和插图。
Additionally, it is supported in Python 2.7, as explained in this comment:
此外,它在 Python 2.7 中受支持,如此评论中所述:
PyCharm supports the typing module from PyPI for Python 2.7, Python 3.2-3.4. For 2.7 you have to put type hints in *.pyi stub files since function annotations were added in Python 3.0.
PyCharm 支持来自 PyPI for Python 2.7、Python 3.2-3.4 的输入模块。对于 2.7,您必须将类型提示放在 *.pyi 存根文件中,因为函数注释是在 Python 3.0 中添加的。
回答by Ani Menon
Adding to Jim's elaborate answer:
添加到吉姆精心制作的答案中:
Check the typing
module-- this module supports type hints as specified by PEP 484.
检查typing
模块- 该模块支持PEP 484指定的类型提示。
For example, the function below takes and returns values of type str
and is annotated as follows:
例如,下面的函数接受并返回类型的值,str
并注释如下:
def greeting(name: str) -> str:
return 'Hello ' + name
The typing
module also supports:
该typing
模块还支持:
- Type aliasing.
- Type hinting for callback functions.
- Generics- Abstract base classes have been extended to support subscription to denote expected types for container elements.
- User-defined generic types- A user-defined class can be defined as a generic class.
- Any type- Every type is a subtype of Any.
回答by Leon Chang
Type-hints is for maintenability and doesn't get interpreted by Python. In the below code, the line "def add(self, ic:int)" doesn't incur an error until the next "return..." line.
类型提示是为了可维护性,不会被 Python 解释。在下面的代码中,“def add(self, ic:int)”行直到下一个“return...”行才会引发错误。
class C1:
def __init__(self):
self.idn = 1
def add(self, ic: int):
return self.idn + ic
c1 = C1()
c1.add(2)
c1.add(c1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'
回答by Noah F. SanTsorvutz
Type hint are a recent addition to a dynamic language where for decades folks swore naming conventions as simple as Hungarian (object label with first letter b = boolian, c = character, d = dictionary, i = integer, l = list, n = numeric, s = string, t= tuple) were not needed, too cumbersome, but now have decided that, oh wait ... it is way too much trouble to use the language (type()) to recognize objects, and our fancy IDEs need help doing anything that complicated, and that dynamically assigned object values make them completely useless anyhow, whereas a simple naming convention could have resolved all of it, for any developer, at a mere glance.
类型提示是最近添加到动态语言中的几十年来人们发誓像匈牙利语一样简单的命名约定(对象标签的首字母 b = boolian,c = 字符,d = 字典,i = 整数,l = 列表,n = 数字, s = string, t= tuple) 是不需要的,太麻烦了,但现在决定了,哦等等......使用语言(type())识别对象太麻烦了,我们花哨的IDE需要帮助做任何复杂的事情,并且动态分配的对象值无论如何使它们完全无用,而简单的命名约定可以解决所有问题,对于任何开发人员来说,只需一瞥。