最近的几个PEP使得编写类型提示变得更加容易。
-
PEP 585为内置类型添加了通用语法,这使得我们可以编写例如
list[int],而不是使用typing.List[int]。 -
PEP 604将
|操作符添加为联合语法,这使得我们可以写例如int | str,而不是typing.Union[int, str],以及int | None,而不是typing.Optional[int]。
PEP 585在Python 3.9中发布,PEP 604将在Python 3.10中发布,目前正在测试中。 但是我们今天可以使用这两种语法,甚至从Python 3.7开始,用Mypy 0.800+和推迟评估的 from __future__ import annotations 。
例如,以这段使用旧语法的代码为例。
from typing import Dict, List, Optional, Union
x: Dict[str, int] = {"a": 1}
y: Union[int, float] = 2.2
z: List[Optional[int]] = [1, None, 3]
我们可以像这样重写它。
from __future__ import annotations
# PEP 585 builtin generics
x: dict[str, int] = {"a": 1}
# PEP 604 union operator
y: int | float = 2.2
# Combining them
z: list[int | None] = [1, None, 3]
但我们所有的旧代码怎么办? 我们现在是不是要用两种方式来做事情,直到我们做大量的手工重写?
不!不!不
感谢pyupgrade 工具,我们可以自动升级我们的语法。pyupgrade 知道如何将许多形式的旧Python语法改写成新的等价物。
我们可以用一个标志来指定我们的目标Python版本,例如:--py39-plus 用于Python 3.9。pyupgrade 将为适当的目标Python版本激活它的PEP 585和604类型提示重写,或者为使用from __future__ import annotations 的文件。
例如,我们可以这样执行上述重写。
$ python -m pip install pyupgrade
Collecting pyupgrade
Downloading pyupgrade-2.18.1-py2.py3-none-any.whl (50 kB)
|████████████████████████████████| 50 kB 1.4 MB/s
Collecting tokenize-rt>=3.2.0
Using cached tokenize_rt-4.1.0-py2.py3-none-any.whl (6.1 kB)
Installing collected packages: tokenize-rt, pyupgrade
Successfully installed pyupgrade-2.18.1 tokenize-rt-4.1.0
$ pyupgrade example.py
Rewriting example.py
这就重写了语法,但保留了导入的内容。
from __future__ import annotations
from typing import Dict, List, Optional, Union
x: dict[str, int] = {"a": 1}
y: int | float = 2.2
z: list[int | None] = [1, None, 3]
很好!现在我们要处理的是旧的typing 导入,它现在没有被使用。我们可以手动删除它们,但是还有一个*工具可以帮助我们:Timothy Crosley 的isort。isort 的--rm 标志允许我们从目标文件中放弃导入。
(*还有一个工具,reorder_python_imports ,也是由Anthony Sottile开发的。它有一个类似的--remove-import 标志。我只是习惯于isort。)
在这种情况下,我们要像这样运行它。
$ python -m pip install isort
Collecting isort
Using cached isort-5.8.0-py3-none-any.whl (103 kB)
Installing collected packages: isort
Successfully installed isort-5.8.0
$ isort --rm 'from typing import Dict' --rm 'from typing import List' --rm 'from typing import Optional' --rm 'from typing import Union' example.py
Fixing /Users/chainz/tmp/hints/example.py
现在我们的代码已经干净地升级到了闪亮的新语法。
from __future__ import annotations
x: dict[str, int] = {"a": 1}
y: int | float = 2.2
z: list[int | None] = [1, None, 3]